{-# LANGUAGE CPP #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE TypeFamilies #-} module Reflex.Patch.Map where import Reflex.Patch.Class import Data.Semigroup import Data.Map (Map) import qualified Data.Map as Map import Data.Maybe -- | A set of changes to a 'Map'. Any element may be inserted/updated or -- deleted. newtype PatchMap k v = PatchMap { unPatchMap :: Map k (Maybe v) } instance Ord k => Patch (PatchMap k v) where type PatchTarget (PatchMap k v) = Map k v apply (PatchMap p) old = Just $! insertions `Map.union` (old `Map.difference` deletions) --TODO: return Nothing sometimes --Note: the strict application here is critical to ensuring that incremental merges don't hold onto all their prerequisite events forever; can we make this more robust? where insertions = Map.mapMaybeWithKey (const id) p deletions = Map.mapMaybeWithKey (const nothingToJust) p nothingToJust = \case Nothing -> Just () Just _ -> Nothing instance Ord k => Semigroup (PatchMap k v) where PatchMap a <> PatchMap b = PatchMap $ a `mappend` b --TODO: Add a semigroup instance for Map -- PatchMap is idempotent, so stimes n is id for every n #if MIN_VERSION_semigroups(0,17,0) stimes = stimesIdempotentMonoid #else times1p n x = case compare n 0 of LT -> error "stimesIdempotentMonoid: negative multiplier" EQ -> mempty GT -> x #endif instance Ord k => Monoid (PatchMap k v) where mempty = PatchMap mempty mappend = (<>) instance Functor (PatchMap k) where fmap f = PatchMap . fmap (fmap f) . unPatchMap -- | Returns all the new elements that will be added to the 'Map' patchMapNewElements :: PatchMap k v -> [v] patchMapNewElements (PatchMap p) = catMaybes $ Map.elems p