{-# LANGUAGE LambdaCase #-}
-- | Additional functions for manipulating 'Map's.
module Data.Map.Misc
  (
  -- * Working with Maps
    diffMapNoEq
  , diffMap
  , applyMap
  , mapPartitionEithers
  , applyMapKeysSet
  ) where

import Data.Align
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe
import Data.Set (Set)
import qualified Data.Set as Set
import Data.These

-- |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@
-- represents an association only present in @old@ but no longer present in @new@.
--
-- Similar to 'diffMap' but doesn't require 'Eq' on the values, thus can't tell if a value has changed or not.
diffMapNoEq :: (Ord k) => Map k v -> Map k v -> Map k (Maybe v)
diffMapNoEq :: Map k v -> Map k v -> Map k (Maybe v)
diffMapNoEq olds :: Map k v
olds news :: Map k v
news = ((These v v -> Maybe (Maybe v))
 -> Map k (These v v) -> Map k (Maybe v))
-> Map k (These v v)
-> (These v v -> Maybe (Maybe v))
-> Map k (Maybe v)
forall a b c. (a -> b -> c) -> b -> a -> c
flip (These v v -> Maybe (Maybe v))
-> Map k (These v v) -> Map k (Maybe v)
forall a b k. (a -> Maybe b) -> Map k a -> Map k b
Map.mapMaybe (Map k v -> Map k v -> Map k (These v v)
forall (f :: * -> *) a b.
Semialign f =>
f a -> f b -> f (These a b)
align Map k v
olds Map k v
news) ((These v v -> Maybe (Maybe v)) -> Map k (Maybe v))
-> (These v v -> Maybe (Maybe v)) -> Map k (Maybe v)
forall a b. (a -> b) -> a -> b
$ \case
  This _ -> Maybe v -> Maybe (Maybe v)
forall a. a -> Maybe a
Just Maybe v
forall a. Maybe a
Nothing
  These _ new :: v
new -> Maybe v -> Maybe (Maybe v)
forall a. a -> Maybe a
Just (Maybe v -> Maybe (Maybe v)) -> Maybe v -> Maybe (Maybe v)
forall a b. (a -> b) -> a -> b
$ v -> Maybe v
forall a. a -> Maybe a
Just v
new
  That new :: v
new -> Maybe v -> Maybe (Maybe v)
forall a. a -> Maybe a
Just (Maybe v -> Maybe (Maybe v)) -> Maybe v -> Maybe (Maybe v)
forall a b. (a -> b) -> a -> b
$ v -> Maybe v
forall a. a -> Maybe a
Just v
new

-- |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
-- present in @old@ or where the value has changed. @Nothing@ represents an association only present in @old@ but no longer present in @new@.
--
-- 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
-- @old@ and @new@ with @Nothing@.
diffMap :: (Ord k, Eq v) => Map k v -> Map k v -> Map k (Maybe v)
diffMap :: Map k v -> Map k v -> Map k (Maybe v)
diffMap olds :: Map k v
olds news :: Map k v
news = ((These v v -> Maybe (Maybe v))
 -> Map k (These v v) -> Map k (Maybe v))
-> Map k (These v v)
-> (These v v -> Maybe (Maybe v))
-> Map k (Maybe v)
forall a b c. (a -> b -> c) -> b -> a -> c
flip (These v v -> Maybe (Maybe v))
-> Map k (These v v) -> Map k (Maybe v)
forall a b k. (a -> Maybe b) -> Map k a -> Map k b
Map.mapMaybe (Map k v -> Map k v -> Map k (These v v)
forall (f :: * -> *) a b.
Semialign f =>
f a -> f b -> f (These a b)
align Map k v
olds Map k v
news) ((These v v -> Maybe (Maybe v)) -> Map k (Maybe v))
-> (These v v -> Maybe (Maybe v)) -> Map k (Maybe v)
forall a b. (a -> b) -> a -> b
$ \case
  This _ -> Maybe v -> Maybe (Maybe v)
forall a. a -> Maybe a
Just Maybe v
forall a. Maybe a
Nothing
  These old :: v
old new :: v
new
    | v
old v -> v -> Bool
forall a. Eq a => a -> a -> Bool
== v
new -> Maybe (Maybe v)
forall a. Maybe a
Nothing
    | Bool
otherwise -> Maybe v -> Maybe (Maybe v)
forall a. a -> Maybe a
Just (Maybe v -> Maybe (Maybe v)) -> Maybe v -> Maybe (Maybe v)
forall a b. (a -> b) -> a -> b
$ v -> Maybe v
forall a. a -> Maybe a
Just v
new
  That new :: v
new -> Maybe v -> Maybe (Maybe v)
forall a. a -> Maybe a
Just (Maybe v -> Maybe (Maybe v)) -> Maybe v -> Maybe (Maybe v)
forall a b. (a -> b) -> a -> b
$ v -> Maybe v
forall a. a -> Maybe a
Just v
new

-- |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@.
--
-- See also 'Data.Patch.Map' and 'Data.Patch.MapWithMove'.
applyMap :: Ord k => Map k (Maybe v) -> Map k v -> Map k v
applyMap :: Map k (Maybe v) -> Map k v -> Map k v
applyMap patch :: Map k (Maybe v)
patch old :: Map k v
old = Map k v
insertions Map k v -> Map k v -> Map k v
forall k a. Ord k => Map k a -> Map k a -> Map k a
`Map.union` (Map k v
old Map k v -> Map k () -> Map k v
forall k a b. Ord k => Map k a -> Map k b -> Map k a
`Map.difference` Map k ()
deletions)
  where (deletions :: Map k ()
deletions, insertions :: Map k v
insertions) = (Maybe v -> Either () v) -> Map k (Maybe v) -> (Map k (), Map k v)
forall a b c k. (a -> Either b c) -> Map k a -> (Map k b, Map k c)
Map.mapEither Maybe v -> Either () v
forall b. Maybe b -> Either () b
maybeToEither Map k (Maybe v)
patch
        maybeToEither :: Maybe b -> Either () b
maybeToEither = \case
          Nothing -> () -> Either () b
forall a b. a -> Either a b
Left ()
          Just r :: b
r -> b -> Either () b
forall a b. b -> Either a b
Right b
r

-- |Split a @'Map' k (Either a b)@ into @Map k a@ and @Map k b@, equivalent to @'Map.mapEither' id@
{-# DEPRECATED mapPartitionEithers "Use 'mapEither' instead" #-}
mapPartitionEithers :: Map k (Either a b) -> (Map k a, Map k b)
mapPartitionEithers :: Map k (Either a b) -> (Map k a, Map k b)
mapPartitionEithers = (Either a b -> Either a b)
-> Map k (Either a b) -> (Map k a, Map k b)
forall a b c k. (a -> Either b c) -> Map k a -> (Map k b, Map k c)
Map.mapEither Either a b -> Either a b
forall a. a -> a
id

-- |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.
--
-- Equivalent to:
--
-- @
--     applyMapKeysSet patch ('Map.keysSet' m) == 'Map.keysSet' ('applyMap' patch m)
-- @
--
-- but avoids the intervening @Map@ and needs no values.
applyMapKeysSet :: Ord k => Map k (Maybe v) -> Set k -> Set k
applyMapKeysSet :: Map k (Maybe v) -> Set k -> Set k
applyMapKeysSet patch :: Map k (Maybe v)
patch old :: Set k
old = Map k (Maybe v) -> Set k
forall k a. Map k a -> Set k
Map.keysSet Map k (Maybe v)
insertions Set k -> Set k -> Set k
forall a. Ord a => Set a -> Set a -> Set a
`Set.union` (Set k
old Set k -> Set k -> Set k
forall a. Ord a => Set a -> Set a -> Set a
`Set.difference` Map k (Maybe v) -> Set k
forall k a. Map k a -> Set k
Map.keysSet Map k (Maybe v)
deletions)
  where (insertions :: Map k (Maybe v)
insertions, deletions :: Map k (Maybe v)
deletions) = (Maybe v -> Bool)
-> Map k (Maybe v) -> (Map k (Maybe v), Map k (Maybe v))
forall a k. (a -> Bool) -> Map k a -> (Map k a, Map k a)
Map.partition Maybe v -> Bool
forall a. Maybe a -> Bool
isJust Map k (Maybe v)
patch