on develop help sign in
reflex/src/Data/Map/Misc.hs
71 lines 3.1 kB history raw
1{-# LANGUAGE LambdaCase #-}
2-- | Additional functions for manipulating 'Map's.
3module Data.Map.Misc
4 (
5 -- * Working with Maps
6 diffMapNoEq
7 , diffMap
8 , applyMap
9 , mapPartitionEithers
10 , applyMapKeysSet
11 ) where
13import Data.Align
14import Data.Map (Map)
15import qualified Data.Map as Map
16import Data.Maybe
17import Data.Set (Set)
18import qualified Data.Set as Set
19import Data.These
21-- |Produce a @'Map' k (Maybe v)@ by comparing two @'Map' k v@s, @old@ and @new@ respectively. @Just@ represents an association present in @new@ and @Nothing@
22-- represents an association only present in @old@ but no longer present in @new@.
23--
24-- Similar to 'diffMap' but doesn't require 'Eq' on the values, thus can't tell if a value has changed or not.
25diffMapNoEq :: (Ord k) => Map k v -> Map k v -> Map k (Maybe v)
26diffMapNoEq olds news = flip Map.mapMaybe (align olds news) $ \case
27 This _ -> Just Nothing
28 These _ new -> Just $ Just new
29 That new -> Just $ Just new
31-- |Produce a @'Map' k (Maybe v)@ by comparing two @'Map' k v@s, @old@ and @new respectively. @Just@ represents an association present in @new@ and either not
32-- present in @old@ or where the value has changed. @Nothing@ represents an association only present in @old@ but no longer present in @new@.
33--
34-- See also 'diffMapNoEq' for a similar but weaker version which does not require 'Eq' on the values but thus can't indicated a value not changing between
35-- @old@ and @new@ with @Nothing@.
36diffMap :: (Ord k, Eq v) => Map k v -> Map k v -> Map k (Maybe v)
37diffMap olds news = flip Map.mapMaybe (align olds news) $ \case
38 This _ -> Just Nothing
39 These old new
40 | old == new -> Nothing
41 | otherwise -> Just $ Just new
42 That new -> Just $ Just new
44-- |Given a @'Map' k (Maybe v)@ representing keys to insert/update (@Just@) or delete (@Nothing@), produce a new map from the given input @'Map' k v@.
45--
46-- See also 'Data.Patch.Map' and 'Data.Patch.MapWithMove'.
47applyMap :: Ord k => Map k (Maybe v) -> Map k v -> Map k v
48applyMap patch old = insertions `Map.union` (old `Map.difference` deletions)
49 where (deletions, insertions) = Map.mapEither maybeToEither patch
50 maybeToEither = \case
51 Nothing -> Left ()
52 Just r -> Right r
54-- |Split a @'Map' k (Either a b)@ into @Map k a@ and @Map k b@, equivalent to @'Map.mapEither' id@
55{-# DEPRECATED mapPartitionEithers "Use 'mapEither' instead" #-}
56mapPartitionEithers :: Map k (Either a b) -> (Map k a, Map k b)
57mapPartitionEithers = Map.mapEither id
59-- |Given a @'Map' k (Maybe v)@ representing keys to insert/update (@Just@) or delete (@Nothing@), produce a new @'Set' k@ from the given input set.
60--
61-- Equivalent to:
62--
63-- @
64-- applyMapKeysSet patch ('Map.keysSet' m) == 'Map.keysSet' ('applyMap' patch m)
65-- @
66--
67-- but avoids the intervening @Map@ and needs no values.
68applyMapKeysSet :: Ord k => Map k (Maybe v) -> Set k -> Set k
69applyMapKeysSet patch old = Map.keysSet insertions `Set.union` (old `Set.difference` Map.keysSet deletions)
70 where (insertions, deletions) = Map.partition isJust patch