Advertisement
Guest User

SetDiff Monoid and group

a guest
Nov 25th, 2012
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. module SetDiff
  2.     ( SetDiff
  3.     , fromList
  4.     , fromSet
  5.     , apply
  6.     , toSet
  7.     , inverse
  8.     ) where
  9.  
  10. import Data.Monoid
  11. import Data.List
  12. import Data.Set (Set, (\\))
  13. import qualified Data.Set as Set
  14. import Data.Map (Map)
  15. import qualified Data.Map as Map
  16.  
  17.  
  18. -- | A 'SetDiff' represents a set of additions and removals of
  19. -- elements from any 'Set' of the same element type.
  20. data SetDiff a = SetDiff (Map a Int) deriving Show
  21.  
  22. -- | Make a 'SetDiff' from a list of elements.  The elements are
  23. -- interpreted as additions.
  24. fromList :: Ord a => [a] -> SetDiff a
  25. fromList xs = SetDiff (Map.fromList (map withOne xs))
  26.     where withOne x = (x, 1)
  27.  
  28. -- | Same as 'fromList' but takes a 'Set' instead.
  29. fromSet :: Ord a => Set a -> SetDiff a
  30. fromSet = fromList . Set.toList
  31.  
  32. -- | Apply a 'SetDiff' to a 'Set'.  Positive elements of the 'SetDiff'
  33. -- will be added to the 'Set', negative ones will be removed.  Zeros
  34. -- will neither be added nor removed.
  35. apply :: Ord a => SetDiff a -> Set a -> Set a
  36. apply (SetDiff m) xs = (xs `Set.difference` neg) `Set.union` pos
  37.     where (neg', nonneg') = partition ((<0) . snd) (Map.toList m)
  38.           neg = Set.fromList (map fst neg')
  39.          pos = Set.fromList (map fst (filter ((>0) . snd) nonneg'))
  40.  
  41. -- | Turn a 'SetDiff' into a 'Set'.  This is the same as applying the
  42. -- 'SetDiff' to an empty 'Set'.
  43. toSet :: Ord a => SetDiff a -> Set a
  44. toSet diff = apply diff mempty
  45.  
  46. -- | 'SetDiff' is a 'Monoid'; you can combine two 'SetDiff's into a
  47. -- composite one that reflects the result of applying both.  Laws:
  48. --
  49. -- > apply mempty xs == xs
  50. -- > apply diff1 (apply diff2 xs) == apply (diff1 `mappend` diff2) xs
  51. instance Ord a => Monoid (SetDiff a) where
  52.     mempty = SetDiff Map.empty
  53.     (SetDiff m0) `mappend` (SetDiff m1) =
  54.         SetDiff (Map.unionWith (+) m0 m1)
  55.  
  56. -- | 'SetDiff' is a group.  Law:
  57. --
  58. -- > diff `mappend` inverse diff == mempty
  59. inverse :: SetDiff a -> SetDiff a
  60. inverse (SetDiff m) = SetDiff (Map.map negate m)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement