patch 0.0.2.0 → 0.0.3.0
raw patch · 11 files changed
+573/−32 lines, 11 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.Monoid.DecidablyEmpty: class Monoid a => DecidablyEmpty a
+ Data.Monoid.DecidablyEmpty: instance (Data.Monoid.DecidablyEmpty.DecidablyEmpty (f p), Data.Monoid.DecidablyEmpty.DecidablyEmpty (g p)) => Data.Monoid.DecidablyEmpty.DecidablyEmpty ((GHC.Generics.:*:) f g p)
+ Data.Monoid.DecidablyEmpty: instance (Data.Monoid.DecidablyEmpty.DecidablyEmpty a, Data.Monoid.DecidablyEmpty.DecidablyEmpty b) => Data.Monoid.DecidablyEmpty.DecidablyEmpty (a, b)
+ Data.Monoid.DecidablyEmpty: instance (Data.Monoid.DecidablyEmpty.DecidablyEmpty a, Data.Monoid.DecidablyEmpty.DecidablyEmpty b, Data.Monoid.DecidablyEmpty.DecidablyEmpty c) => Data.Monoid.DecidablyEmpty.DecidablyEmpty (a, b, c)
+ Data.Monoid.DecidablyEmpty: instance (Data.Monoid.DecidablyEmpty.DecidablyEmpty a, Data.Monoid.DecidablyEmpty.DecidablyEmpty b, Data.Monoid.DecidablyEmpty.DecidablyEmpty c, Data.Monoid.DecidablyEmpty.DecidablyEmpty d) => Data.Monoid.DecidablyEmpty.DecidablyEmpty (a, b, c, d)
+ Data.Monoid.DecidablyEmpty: instance (Data.Monoid.DecidablyEmpty.DecidablyEmpty a, Data.Monoid.DecidablyEmpty.DecidablyEmpty b, Data.Monoid.DecidablyEmpty.DecidablyEmpty c, Data.Monoid.DecidablyEmpty.DecidablyEmpty d, Data.Monoid.DecidablyEmpty.DecidablyEmpty e) => Data.Monoid.DecidablyEmpty.DecidablyEmpty (a, b, c, d, e)
+ Data.Monoid.DecidablyEmpty: instance (Data.Monoid.DecidablyEmpty.DecidablyEmpty a, GHC.Num.Num a) => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Semigroup.Internal.Sum a)
+ Data.Monoid.DecidablyEmpty: instance (GHC.Classes.Ord a, GHC.Enum.Bounded a) => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Semigroup.Max a)
+ Data.Monoid.DecidablyEmpty: instance (GHC.Classes.Ord a, GHC.Enum.Bounded a) => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Semigroup.Min a)
+ Data.Monoid.DecidablyEmpty: instance (GHC.Num.Num a, Data.Monoid.DecidablyEmpty.DecidablyEmpty a) => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Semigroup.Internal.Product a)
+ Data.Monoid.DecidablyEmpty: instance Data.GADT.Compare.GCompare k => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Dependent.Map.Internal.DMap k v)
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty ()
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.IntMap.Internal.IntMap v)
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Monoid.First a)
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Monoid.Last a)
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Proxy.Proxy s)
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Sequence.Internal.Seq v)
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty (GHC.Generics.U1 p)
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty (f (g p)) => Data.Monoid.DecidablyEmpty.DecidablyEmpty ((GHC.Generics.:.:) f g p)
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty (f p) => Data.Monoid.DecidablyEmpty.DecidablyEmpty (GHC.Generics.M1 i c f p)
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty (f p) => Data.Monoid.DecidablyEmpty.DecidablyEmpty (GHC.Generics.Rec1 f p)
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty Data.IntSet.Internal.IntSet
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty Data.Semigroup.Internal.All
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty Data.Semigroup.Internal.Any
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty GHC.Types.Ordering
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty [a]
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty a => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Functor.Const.Const a b)
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty a => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Functor.Identity.Identity a)
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty a => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Ord.Down a)
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty a => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Semigroup.Internal.Dual a)
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty c => Data.Monoid.DecidablyEmpty.DecidablyEmpty (GHC.Generics.K1 i c p)
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty m => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Semigroup.WrappedMonoid m)
+ Data.Monoid.DecidablyEmpty: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty p => Data.Monoid.DecidablyEmpty.DecidablyEmpty (GHC.Generics.Par1 p)
+ Data.Monoid.DecidablyEmpty: instance GHC.Base.Semigroup a => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Semigroup.Option a)
+ Data.Monoid.DecidablyEmpty: instance GHC.Base.Semigroup a => Data.Monoid.DecidablyEmpty.DecidablyEmpty (GHC.Maybe.Maybe a)
+ Data.Monoid.DecidablyEmpty: instance GHC.Classes.Ord k => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Map.Internal.Map k v)
+ Data.Monoid.DecidablyEmpty: instance GHC.Classes.Ord k => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Set.Internal.Set k)
+ Data.Monoid.DecidablyEmpty: isEmpty :: (DecidablyEmpty a, Eq a) => a -> Bool
+ Data.Patch.Class: instance Data.Patch.Class.Patch (Data.Proxy.Proxy a)
+ Data.Patch.DMap: instance forall k1 (k2 :: k1 -> *) (v :: k1 -> *). Data.GADT.Compare.GCompare k2 => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Patch.DMap.PatchDMap k2 v)
+ Data.Patch.DMapWithMove: instance forall k1 (k2 :: k1 -> *) (v :: k1 -> *). Data.GADT.Compare.GCompare k2 => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Patch.DMapWithMove.PatchDMapWithMove k2 v)
+ Data.Patch.IntMap: instance Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Patch.IntMap.PatchIntMap a)
+ Data.Patch.Map: instance GHC.Classes.Ord k => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Patch.Map.PatchMap k v)
+ Data.Patch.MapWithPatchingMove: Fixup_Delete :: Fixup k v
+ Data.Patch.MapWithPatchingMove: Fixup_Update :: These (From k v) (To k) -> Fixup k v
+ Data.Patch.MapWithPatchingMove: From_Delete :: From k p
+ Data.Patch.MapWithPatchingMove: From_Insert :: PatchTarget p -> From k p
+ Data.Patch.MapWithPatchingMove: From_Move :: !k -> !p -> From k p
+ Data.Patch.MapWithPatchingMove: NodeInfo :: !From k p -> !To k -> NodeInfo k p
+ Data.Patch.MapWithPatchingMove: PatchMapWithPatchingMove :: Map k (NodeInfo k p) -> PatchMapWithPatchingMove k p
+ Data.Patch.MapWithPatchingMove: [_nodeInfo_from] :: NodeInfo k p -> !From k p
+ Data.Patch.MapWithPatchingMove: [_nodeInfo_to] :: NodeInfo k p -> !To k
+ Data.Patch.MapWithPatchingMove: [unPatchMapWithPatchingMove] :: PatchMapWithPatchingMove k p -> Map k (NodeInfo k p)
+ Data.Patch.MapWithPatchingMove: bitraverseFrom :: Applicative f => (k0 -> f k1) -> (p0 -> f p1) -> (PatchTarget p0 -> f (PatchTarget p1)) -> From k0 p0 -> f (From k1 p1)
+ Data.Patch.MapWithPatchingMove: bitraverseNodeInfo :: Applicative f => (k0 -> f k1) -> (p0 -> f p1) -> (PatchTarget p0 -> f (PatchTarget p1)) -> NodeInfo k0 p0 -> f (NodeInfo k1 p1)
+ Data.Patch.MapWithPatchingMove: data Fixup k v
+ Data.Patch.MapWithPatchingMove: data From k p
+ Data.Patch.MapWithPatchingMove: data NodeInfo k p
+ Data.Patch.MapWithPatchingMove: deleteMapKey :: k -> PatchMapWithPatchingMove k v
+ Data.Patch.MapWithPatchingMove: insertMapKey :: k -> PatchTarget p -> PatchMapWithPatchingMove k p
+ Data.Patch.MapWithPatchingMove: instance (Data.Patch.MapWithPatchingMove.PatchMapWithPatchingMove k1 p1 Data.Type.Equality.~ t) => Control.Lens.Wrapped.Rewrapped (Data.Patch.MapWithPatchingMove.PatchMapWithPatchingMove k2 p2) t
+ Data.Patch.MapWithPatchingMove: instance (GHC.Classes.Eq k, GHC.Classes.Eq p, GHC.Classes.Eq (Data.Patch.Class.PatchTarget p)) => GHC.Classes.Eq (Data.Patch.MapWithPatchingMove.From k p)
+ Data.Patch.MapWithPatchingMove: instance (GHC.Classes.Eq k, GHC.Classes.Eq p, GHC.Classes.Eq (Data.Patch.Class.PatchTarget p)) => GHC.Classes.Eq (Data.Patch.MapWithPatchingMove.NodeInfo k p)
+ Data.Patch.MapWithPatchingMove: instance (GHC.Classes.Eq k, GHC.Classes.Eq p, GHC.Classes.Eq (Data.Patch.Class.PatchTarget p)) => GHC.Classes.Eq (Data.Patch.MapWithPatchingMove.PatchMapWithPatchingMove k p)
+ Data.Patch.MapWithPatchingMove: instance (GHC.Classes.Ord k, Data.Monoid.DecidablyEmpty.DecidablyEmpty p, Data.Patch.Class.Patch p) => Data.Monoid.DecidablyEmpty.DecidablyEmpty (Data.Patch.MapWithPatchingMove.PatchMapWithPatchingMove k p)
+ Data.Patch.MapWithPatchingMove: instance (GHC.Classes.Ord k, Data.Monoid.DecidablyEmpty.DecidablyEmpty p, Data.Patch.Class.Patch p) => GHC.Base.Monoid (Data.Patch.MapWithPatchingMove.PatchMapWithPatchingMove k p)
+ Data.Patch.MapWithPatchingMove: instance (GHC.Classes.Ord k, Data.Monoid.DecidablyEmpty.DecidablyEmpty p, Data.Patch.Class.Patch p) => GHC.Base.Semigroup (Data.Patch.MapWithPatchingMove.PatchMapWithPatchingMove k p)
+ Data.Patch.MapWithPatchingMove: instance (GHC.Classes.Ord k, Data.Patch.Class.Patch p) => Data.Patch.Class.Patch (Data.Patch.MapWithPatchingMove.PatchMapWithPatchingMove k p)
+ Data.Patch.MapWithPatchingMove: instance (GHC.Classes.Ord k, GHC.Classes.Ord p, GHC.Classes.Ord (Data.Patch.Class.PatchTarget p)) => GHC.Classes.Ord (Data.Patch.MapWithPatchingMove.From k p)
+ Data.Patch.MapWithPatchingMove: instance (GHC.Classes.Ord k, GHC.Classes.Ord p, GHC.Classes.Ord (Data.Patch.Class.PatchTarget p)) => GHC.Classes.Ord (Data.Patch.MapWithPatchingMove.NodeInfo k p)
+ Data.Patch.MapWithPatchingMove: instance (GHC.Classes.Ord k, GHC.Classes.Ord p, GHC.Classes.Ord (Data.Patch.Class.PatchTarget p)) => GHC.Classes.Ord (Data.Patch.MapWithPatchingMove.PatchMapWithPatchingMove k p)
+ Data.Patch.MapWithPatchingMove: instance (GHC.Classes.Ord k, GHC.Read.Read k, GHC.Read.Read p, GHC.Read.Read (Data.Patch.Class.PatchTarget p)) => GHC.Read.Read (Data.Patch.MapWithPatchingMove.PatchMapWithPatchingMove k p)
+ Data.Patch.MapWithPatchingMove: instance (GHC.Read.Read k, GHC.Read.Read p, GHC.Read.Read (Data.Patch.Class.PatchTarget p)) => GHC.Read.Read (Data.Patch.MapWithPatchingMove.From k p)
+ Data.Patch.MapWithPatchingMove: instance (GHC.Read.Read k, GHC.Read.Read p, GHC.Read.Read (Data.Patch.Class.PatchTarget p)) => GHC.Read.Read (Data.Patch.MapWithPatchingMove.NodeInfo k p)
+ Data.Patch.MapWithPatchingMove: instance (GHC.Show.Show k, GHC.Show.Show p, GHC.Show.Show (Data.Patch.Class.PatchTarget p)) => GHC.Show.Show (Data.Patch.MapWithPatchingMove.From k p)
+ Data.Patch.MapWithPatchingMove: instance (GHC.Show.Show k, GHC.Show.Show p, GHC.Show.Show (Data.Patch.Class.PatchTarget p)) => GHC.Show.Show (Data.Patch.MapWithPatchingMove.NodeInfo k p)
+ Data.Patch.MapWithPatchingMove: instance (GHC.Show.Show k, GHC.Show.Show p, GHC.Show.Show (Data.Patch.Class.PatchTarget p)) => GHC.Show.Show (Data.Patch.MapWithPatchingMove.PatchMapWithPatchingMove k p)
+ Data.Patch.MapWithPatchingMove: instance Control.Lens.Wrapped.Wrapped (Data.Patch.MapWithPatchingMove.PatchMapWithPatchingMove k p)
+ Data.Patch.MapWithPatchingMove: moveMapKey :: (DecidablyEmpty p, Patch p) => Ord k => k -> k -> PatchMapWithPatchingMove k p
+ Data.Patch.MapWithPatchingMove: newtype PatchMapWithPatchingMove k p
+ Data.Patch.MapWithPatchingMove: nodeInfoMapFrom :: (From k v -> From k v) -> NodeInfo k v -> NodeInfo k v
+ Data.Patch.MapWithPatchingMove: nodeInfoMapMFrom :: Functor f => (From k v -> f (From k v)) -> NodeInfo k v -> f (NodeInfo k v)
+ Data.Patch.MapWithPatchingMove: nodeInfoSetTo :: To k -> NodeInfo k v -> NodeInfo k v
+ Data.Patch.MapWithPatchingMove: patchMapWithPatchingMove :: Ord k => Map k (NodeInfo k p) -> Maybe (PatchMapWithPatchingMove k p)
+ Data.Patch.MapWithPatchingMove: patchMapWithPatchingMoveInsertAll :: Map k (PatchTarget p) -> PatchMapWithPatchingMove k p
+ Data.Patch.MapWithPatchingMove: patchMapWithPatchingMoveNewElements :: PatchMapWithPatchingMove k p -> [PatchTarget p]
+ Data.Patch.MapWithPatchingMove: patchMapWithPatchingMoveNewElementsMap :: PatchMapWithPatchingMove k p -> Map k (PatchTarget p)
+ Data.Patch.MapWithPatchingMove: patchThatChangesAndSortsMapWith :: forall k p. (Ord k, Ord (PatchTarget p), Monoid p) => (PatchTarget p -> PatchTarget p -> Ordering) -> Map k (PatchTarget p) -> Map k (PatchTarget p) -> PatchMapWithPatchingMove k p
+ Data.Patch.MapWithPatchingMove: patchThatChangesMap :: (Ord k, Ord (PatchTarget p), Monoid p) => Map k (PatchTarget p) -> Map k (PatchTarget p) -> PatchMapWithPatchingMove k p
+ Data.Patch.MapWithPatchingMove: patchThatSortsMapWith :: (Ord k, Monoid p) => (PatchTarget p -> PatchTarget p -> Ordering) -> Map k (PatchTarget p) -> PatchMapWithPatchingMove k p
+ Data.Patch.MapWithPatchingMove: swapMapKey :: (DecidablyEmpty p, Patch p) => Ord k => k -> k -> PatchMapWithPatchingMove k p
+ Data.Patch.MapWithPatchingMove: type To = Maybe
+ Data.Patch.MapWithPatchingMove: unsafePatchMapWithPatchingMove :: Map k (NodeInfo k p) -> PatchMapWithPatchingMove k p
Files
- ChangeLog.md +6/−0
- patch.cabal +3/−1
- src/Data/Monoid/DecidablyEmpty.hs +115/−0
- src/Data/Patch.hs +22/−14
- src/Data/Patch/Class.hs +9/−0
- src/Data/Patch/DMap.hs +9/−0
- src/Data/Patch/DMapWithMove.hs +8/−1
- src/Data/Patch/IntMap.hs +9/−6
- src/Data/Patch/Map.hs +9/−8
- src/Data/Patch/MapWithMove.hs +5/−2
- src/Data/Patch/MapWithPatchingMove.hs +378/−0
ChangeLog.md view
@@ -1,5 +1,11 @@ # Revision history for patch +## 0.0.3.0++* Create `PatchMapWithPatchingMove` variant which supports moves with a patch.++* Create `DecidablyEmpty` subclass of `Monoid`.+ ## 0.0.2.0 * Consistently provide:
patch.cabal view
@@ -1,5 +1,5 @@ Name: patch-Version: 0.0.2.0+Version: 0.0.3.0 Synopsis: Infrastructure for writing patches which act on other types. Description: In this library, a patch is something which can be applied, analogous to a@@ -41,6 +41,7 @@ , witherable >= 0.3 && < 0.3.2 exposed-modules: Data.Functor.Misc+ , Data.Monoid.DecidablyEmpty , Data.Patch , Data.Patch.Class , Data.Patch.DMap@@ -48,6 +49,7 @@ , Data.Patch.IntMap , Data.Patch.Map , Data.Patch.MapWithMove+ , Data.Patch.MapWithPatchingMove ghc-options: -Wall -fwarn-redundant-constraints -fwarn-tabs
+ src/Data/Monoid/DecidablyEmpty.hs view
@@ -0,0 +1,115 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeOperators #-}++-- TODO upstream somwhere else?+module Data.Monoid.DecidablyEmpty where++import Data.Functor.Identity+import Data.Functor.Const+import Data.Monoid+import Data.Maybe (isNothing)+#if MIN_VERSION_base(4,11,0)+import Data.Ord+#endif+import Data.Proxy+import Data.Semigroup hiding (First, Last)+#if MIN_VERSION_base(4,12,0)+import GHC.Generics+#endif++import qualified Data.IntSet as IntSet+import qualified Data.IntMap as IntMap+import qualified Data.Map as Map+import qualified Data.Sequence as Seq+import qualified Data.Set as Set++import Data.GADT.Compare+import qualified Data.Dependent.Map as DMap++-- | A 'DecidablyEmpty' is one where it can be computed whether or not an+-- arbitrary value is 'mempty'.+--+-- By using this class rather than 'Eq', we avoid unnecessary constraining the+-- contents of 'Functor's. This makes it possible to efficiently combine and/or+-- nest patch maps with 'Eq'-lacking values (e.g. functions) at the leaves.+class Monoid a => DecidablyEmpty a where+ isEmpty :: a -> Bool+ default isEmpty :: Eq a => a -> Bool+ isEmpty = (==) mempty++-- base++instance DecidablyEmpty Ordering+instance DecidablyEmpty ()+instance DecidablyEmpty Any+instance DecidablyEmpty All+-- instance DecidablyEmpty Lifetime+-- instance DecidablyEmpty Event+instance DecidablyEmpty [a] where+ isEmpty = null+instance+#if MIN_VERSION_base(4,11,0)+ Semigroup a+#else+ Monoid a+#endif+ => DecidablyEmpty (Maybe a) where+ isEmpty = isNothing+deriving instance (Num a, DecidablyEmpty a) => DecidablyEmpty (Product a)+deriving instance (DecidablyEmpty a, Num a) => DecidablyEmpty (Sum a)+deriving instance DecidablyEmpty a => DecidablyEmpty (Dual a)+instance DecidablyEmpty (First a) where+ isEmpty (First a) = isNothing a+instance DecidablyEmpty (Last a) where+ isEmpty (Last a) = isNothing a+deriving instance DecidablyEmpty a => DecidablyEmpty (Identity a)+instance Semigroup a => DecidablyEmpty (Option a) where+ isEmpty (Option a) = isNothing a+deriving instance DecidablyEmpty m => DecidablyEmpty (WrappedMonoid m)+instance (Ord a, Bounded a) => DecidablyEmpty (Max a)+instance (Ord a, Bounded a) => DecidablyEmpty (Min a)+instance DecidablyEmpty (Proxy s)+deriving instance DecidablyEmpty a => DecidablyEmpty (Const a b)+#if MIN_VERSION_base(4,11,0)+deriving instance DecidablyEmpty a => DecidablyEmpty (Down a)+#endif+#if MIN_VERSION_base(4,12,0)+deriving instance DecidablyEmpty p => DecidablyEmpty (Par1 p)+instance DecidablyEmpty (U1 p)+deriving instance DecidablyEmpty (f p) => DecidablyEmpty (Rec1 f p)+deriving instance DecidablyEmpty (f p) => DecidablyEmpty (M1 i c f p)+deriving instance DecidablyEmpty c => DecidablyEmpty (K1 i c p)+instance (DecidablyEmpty (f p), DecidablyEmpty (g p)) => DecidablyEmpty ((f :*: g) p) where+ isEmpty (x :*: y) = isEmpty x && isEmpty y+deriving instance DecidablyEmpty (f (g p)) => DecidablyEmpty ((f :.: g) p)+#endif++instance (DecidablyEmpty a, DecidablyEmpty b) => DecidablyEmpty (a, b) where+ isEmpty (a, b) = isEmpty a && isEmpty b+instance (DecidablyEmpty a, DecidablyEmpty b, DecidablyEmpty c) => DecidablyEmpty (a, b, c) where+ isEmpty (a, b, c) = isEmpty a && isEmpty b && isEmpty c+instance (DecidablyEmpty a, DecidablyEmpty b, DecidablyEmpty c, DecidablyEmpty d) => DecidablyEmpty (a, b, c, d) where+ isEmpty (a, b, c, d) = isEmpty a && isEmpty b && isEmpty c && isEmpty d+instance (DecidablyEmpty a, DecidablyEmpty b, DecidablyEmpty c, DecidablyEmpty d, DecidablyEmpty e) => DecidablyEmpty (a, b, c, d, e) where+ isEmpty (a, b, c, d, e) = isEmpty a && isEmpty b && isEmpty c && isEmpty d && isEmpty e++-- containers++instance DecidablyEmpty IntSet.IntSet where+ isEmpty = IntSet.null+instance DecidablyEmpty (IntMap.IntMap v) where+ isEmpty = IntMap.null+instance Ord k => DecidablyEmpty (Map.Map k v) where+ isEmpty = Map.null+instance DecidablyEmpty (Seq.Seq v) where+ isEmpty = Seq.null+instance Ord k => DecidablyEmpty (Set.Set k) where+ isEmpty = Set.null++-- dependent-map++instance GCompare k => DecidablyEmpty (DMap.DMap k v) where+ isEmpty = DMap.null
src/Data/Patch.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TypeFamilies #-}@@ -12,24 +13,31 @@ , module X ) where +import Control.Applicative+import Data.Functor.Const (Const (..))+import Data.Functor.Identity+import Data.Map.Monoidal (MonoidalMap)+import Data.Proxy+#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup (Semigroup (..))+#endif+import GHC.Generics+ import Data.Patch.Class as X import Data.Patch.DMap as X hiding (getDeletions)-import Data.Patch.DMapWithMove as X (PatchDMapWithMove, const2PatchDMapWithMoveWith, mapPatchDMapWithMove,- patchDMapWithMoveToPatchMapWithMoveWith,- traversePatchDMapWithMoveWithKey, unPatchDMapWithMove,- unsafePatchDMapWithMove, weakenPatchDMapWithMoveWith)+import Data.Patch.DMapWithMove as X+ ( PatchDMapWithMove, const2PatchDMapWithMoveWith, mapPatchDMapWithMove+ , patchDMapWithMoveToPatchMapWithMoveWith+ , traversePatchDMapWithMoveWithKey, unPatchDMapWithMove+ , unsafePatchDMapWithMove, weakenPatchDMapWithMoveWith+ ) import Data.Patch.IntMap as X hiding (getDeletions) import Data.Patch.Map as X-import Data.Patch.MapWithMove as X (PatchMapWithMove, patchMapWithMoveNewElements,- patchMapWithMoveNewElementsMap, unPatchMapWithMove,- unsafePatchMapWithMove)-import Data.Map.Monoidal (MonoidalMap)-import Data.Semigroup (Semigroup (..), (<>))-import GHC.Generics-import Data.Functor.Identity-import Data.Functor.Const-import Data.Proxy-import Control.Applicative+import Data.Patch.MapWithMove as X+ ( PatchMapWithMove, patchMapWithMoveNewElements+ , patchMapWithMoveNewElementsMap, unPatchMapWithMove+ , unsafePatchMapWithMove+ ) -- | A 'Group' is a 'Monoid' where every element has an inverse. class (Semigroup q, Monoid q) => Group q where
src/Data/Patch/Class.hs view
@@ -1,10 +1,14 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE TypeFamilies #-} -- | The interface for types which represent changes made to other types module Data.Patch.Class where import Data.Functor.Identity import Data.Maybe+#if !MIN_VERSION_base(4,11,0) import Data.Semigroup (Semigroup(..))+#endif+import Data.Proxy -- | A 'Patch' type represents a kind of change made to a datastructure. --@@ -24,6 +28,11 @@ instance Patch (Identity a) where type PatchTarget (Identity a) = a apply (Identity a) _ = Just a++-- | 'Proxy' can be used as a 'Patch' that does nothing.+instance Patch (Proxy a) where+ type PatchTarget (Proxy a) = a+ apply ~Proxy _ = Nothing -- | Like '(.)', but composes functions that return patches rather than -- functions that return new values. The Semigroup instance for patches must
src/Data/Patch/DMap.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE PolyKinds #-}@@ -5,6 +6,7 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TypeFamilies #-}+ -- | 'Patch'es on 'DMap' that consist only of insertions (or overwrites) and deletions. module Data.Patch.DMap where @@ -18,7 +20,10 @@ import Data.Functor.Misc import qualified Data.IntMap as IntMap import qualified Data.Map as Map+import Data.Monoid.DecidablyEmpty+#if !MIN_VERSION_base(4,11,0) import Data.Semigroup (Semigroup (..))+#endif import Data.Some (Some) -- | A set of changes to a 'DMap'. Any element may be inserted/updated or deleted.@@ -29,6 +34,10 @@ deriving instance GCompare k => Semigroup (PatchDMap k v) deriving instance GCompare k => Monoid (PatchDMap k v)++-- It won't let me derive for some reason+instance GCompare k => DecidablyEmpty (PatchDMap k v) where+ isEmpty (PatchDMap m) = DMap.null m -- | Apply the insertions or deletions to a given 'DMap'. instance GCompare k => Patch (PatchDMap k v) where
src/Data/Patch/DMapWithMove.hs view
@@ -29,7 +29,10 @@ import Data.GADT.Show (GShow, gshow) import qualified Data.Map as Map import Data.Maybe-import Data.Semigroup (Semigroup (..), (<>))+import Data.Monoid.DecidablyEmpty+#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup (Semigroup (..))+#endif import Data.Some (Some(Some)) import Data.These @@ -41,6 +44,10 @@ -- * A key should not move to itself. -- * A move should always be represented with both the destination key (as a 'From_Move') and the source key (as a @'ComposeMaybe' ('Just' destination)@) newtype PatchDMapWithMove k v = PatchDMapWithMove (DMap k (NodeInfo k v))++-- It won't let me derive for some reason+instance GCompare k => DecidablyEmpty (PatchDMapWithMove k v) where+ isEmpty (PatchDMapWithMove m) = DMap.null m -- |Structure which represents what changes apply to a particular key. @_nodeInfo_from@ specifies what happens to this key, and in particular what other key -- the current key is moving from, while @_nodeInfo_to@ specifies what key the current key is moving to if involved in a move.
src/Data/Patch/IntMap.hs view
@@ -1,7 +1,9 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} @@ -13,7 +15,10 @@ import Data.IntMap.Strict (IntMap) import qualified Data.IntMap.Strict as IntMap import Data.Maybe-import Data.Semigroup+import Data.Monoid.DecidablyEmpty+#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup (Semigroup (..))+#endif import Data.Patch.Class -- | 'Patch' for 'IntMap' which represents insertion or deletion of keys in the mapping.@@ -21,16 +26,14 @@ -- and @Nothing@ means delete. newtype PatchIntMap a = PatchIntMap { unPatchIntMap :: IntMap (Maybe a) } deriving ( Show, Read, Eq, Ord- , Functor, Foldable, Traversable, Monoid+ , Functor, Foldable, Traversable+ , Monoid, DecidablyEmpty ) -- | @a <> b@ will apply the changes of @b@ and then apply the changes of @a@. -- If the same key is modified by both patches, the one on the left will take -- precedence.-instance Semigroup (PatchIntMap v) where- PatchIntMap a <> PatchIntMap b = PatchIntMap $ a `mappend` b --TODO: Add a semigroup instance for Map- -- PatchMap is idempotent, so stimes n is id for every n- stimes = stimesIdempotentMonoid+deriving instance Semigroup (PatchIntMap v) makeWrapped ''PatchIntMap
src/Data/Patch/Map.hs view
@@ -1,5 +1,7 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE StandaloneDeriving #-}@@ -16,7 +18,8 @@ import Data.Map (Map) import qualified Data.Map as Map import Data.Maybe-import Data.Semigroup+import Data.Monoid.DecidablyEmpty+import Data.Semigroup (Semigroup (..), stimesIdempotentMonoid) -- | A set of changes to a 'Map'. Any element may be inserted/updated or -- deleted. Insertions are represented as values wrapped in 'Just', while@@ -24,11 +27,14 @@ newtype PatchMap k v = PatchMap { unPatchMap :: Map k (Maybe v) } deriving ( Show, Read, Eq, Ord , Foldable, Traversable+ , DecidablyEmpty ) -- | 'fmap'ping a 'PatchMap' will alter all of the values it will insert. -- Deletions are unaffected. deriving instance Functor (PatchMap k)+-- | The empty 'PatchMap' contains no insertions or deletions+deriving instance Ord k => Monoid (PatchMap k v) -- | @a <> b@ will apply the changes of @b@ and then apply the changes of @a@. -- If the same key is modified by both patches, the one on the left will take@@ -38,8 +44,6 @@ -- PatchMap is idempotent, so stimes n is id for every n stimes = stimesIdempotentMonoid -makeWrapped ''PatchMap- -- | Apply the insertions or deletions to a given 'Map'. instance Ord k => Patch (PatchMap k v) where type PatchTarget (PatchMap k v) = Map k v@@ -57,11 +61,6 @@ itraverse = itraversed . Indexed itraversed = _Wrapped .> itraversed <. traversed --- | The empty 'PatchMap' contains no insertions or deletions-instance Ord k => Monoid (PatchMap k v) where- mempty = PatchMap mempty- mappend = (<>)- -- | Returns all the new elements that will be added to the 'Map' patchMapNewElements :: PatchMap k v -> [v] patchMapNewElements (PatchMap p) = catMaybes $ Map.elems p@@ -69,3 +68,5 @@ -- | Returns all the new elements that will be added to the 'Map' patchMapNewElementsMap :: PatchMap k v -> Map k v patchMapNewElementsMap (PatchMap p) = Map.mapMaybe id p++makeWrapped ''PatchMap
src/Data/Patch/MapWithMove.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}@@ -24,7 +25,9 @@ import Data.Map (Map) import qualified Data.Map as Map import Data.Maybe-import Data.Semigroup (Semigroup (..), (<>))+#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup (Semigroup (..))+#endif import qualified Data.Set as Set import Data.These (These(..)) import Data.Tuple@@ -199,7 +202,7 @@ putRemainingKeys $ Set.delete k fromKs return $ NodeInfo (From_Move k) $ Just undefined -- There's an existing value, and it's here, so no patch necessary else do- (fromK, remainingKeys) <- return . fromJust $ Set.minView fromKs -- There's an existing value, but it's not here; move it here+ (fromK, remainingKeys) <- return . fromMaybe (error "patchThatChangesMap: impossible: fromKs was empty") $ Set.minView fromKs -- There's an existing value, but it's not here; move it here putRemainingKeys remainingKeys return $ NodeInfo (From_Move fromK) $ Just undefined Map.traverseWithKey f newByIndex
+ src/Data/Patch/MapWithPatchingMove.hs view
@@ -0,0 +1,378 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}++-- | 'Patch'es on 'Map' that can insert, delete, and move values from one key to+-- another+module Data.Patch.MapWithPatchingMove where++import Data.Patch.Class++import Control.Arrow+import Control.Lens.TH (makeWrapped)+import Control.Monad.Trans.State+import Data.Foldable+import Data.Function+import Data.List+import Data.Map (Map)+import qualified Data.Map as Map+import Data.Maybe+#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup (Semigroup (..))+#endif+import Data.Monoid.DecidablyEmpty+import qualified Data.Set as Set+import Data.These (These (..))+import Data.Tuple++-- | Patch a Map with additions, deletions, and moves. Invariant: If key @k1@+-- is coming from @From_Move k2@, then key @k2@ should be going to @Just k1@,+-- and vice versa. There should never be any unpaired From/To keys.+newtype PatchMapWithPatchingMove k p = PatchMapWithPatchingMove+ { -- | Extract the internal representation of the 'PatchMapWithPatchingMove'+ unPatchMapWithPatchingMove :: Map k (NodeInfo k p)+ }++deriving instance (Show k, Show p, Show (PatchTarget p)) => Show (PatchMapWithPatchingMove k p)+deriving instance (Ord k, Read k, Read p, Read (PatchTarget p)) => Read (PatchMapWithPatchingMove k p)+deriving instance (Eq k, Eq p, Eq (PatchTarget p)) => Eq (PatchMapWithPatchingMove k p)+deriving instance (Ord k, Ord p, Ord (PatchTarget p)) => Ord (PatchMapWithPatchingMove k p)++deriving instance ( Ord k+#if !MIN_VERSION_base(4,11,0)+ , Semigroup p+#endif+ , DecidablyEmpty p+ , Patch p+ ) => DecidablyEmpty (PatchMapWithPatchingMove k p)++-- | Holds the information about each key: where its new value should come from,+-- and where its old value should go to+data NodeInfo k p = NodeInfo+ { _nodeInfo_from :: !(From k p)+ -- ^ Where do we get the new value for this key?+ , _nodeInfo_to :: !(To k)+ -- ^ If the old value is being kept (i.e. moved rather than deleted or+ -- replaced), where is it going?+ }+deriving instance (Show k, Show p, Show (PatchTarget p)) => Show (NodeInfo k p)+deriving instance (Read k, Read p, Read (PatchTarget p)) => Read (NodeInfo k p)+deriving instance (Eq k, Eq p, Eq (PatchTarget p)) => Eq (NodeInfo k p)+deriving instance (Ord k, Ord p, Ord (PatchTarget p)) => Ord (NodeInfo k p)++bitraverseNodeInfo+ :: Applicative f+ => (k0 -> f k1)+ -> (p0 -> f p1)+ -> (PatchTarget p0 -> f (PatchTarget p1))+ -> NodeInfo k0 p0 -> f (NodeInfo k1 p1)+bitraverseNodeInfo fk fp fpt (NodeInfo from to) = NodeInfo+ <$> bitraverseFrom fk fp fpt from+ <*> traverse fk to++-- | Describe how a key's new value should be produced+data From k p+ = From_Insert (PatchTarget p) -- ^ Insert the given value here+ | From_Delete -- ^ Delete the existing value, if any, from here+ | From_Move !k !p -- ^ Move the value here from the given key, and apply the given patch++bitraverseFrom+ :: Applicative f+ => (k0 -> f k1)+ -> (p0 -> f p1)+ -> (PatchTarget p0 -> f (PatchTarget p1))+ -> From k0 p0 -> f (From k1 p1)+bitraverseFrom fk fp fpt = \case+ From_Insert pt -> From_Insert <$> fpt pt+ From_Delete -> pure From_Delete+ From_Move k p -> From_Move <$> fk k <*> fp p++deriving instance (Show k, Show p, Show (PatchTarget p)) => Show (From k p)+deriving instance (Read k, Read p, Read (PatchTarget p)) => Read (From k p)+deriving instance (Eq k, Eq p, Eq (PatchTarget p)) => Eq (From k p)+deriving instance (Ord k, Ord p, Ord (PatchTarget p)) => Ord (From k p)++-- | Describe where a key's old value will go. If this is 'Just', that means+-- the key's old value will be moved to the given other key; if it is 'Nothing',+-- that means it will be deleted.+type To = Maybe++-- | Create a 'PatchMapWithPatchingMove', validating it+patchMapWithPatchingMove+ :: Ord k => Map k (NodeInfo k p) -> Maybe (PatchMapWithPatchingMove k p)+patchMapWithPatchingMove m = if valid then Just $ PatchMapWithPatchingMove m else Nothing+ where valid = forwardLinks == backwardLinks+ forwardLinks = Map.mapMaybe _nodeInfo_to m+ backwardLinks = Map.fromList $ catMaybes $ flip fmap (Map.toList m) $ \(to, p) ->+ case _nodeInfo_from p of+ From_Move from _ -> Just (from, to)+ _ -> Nothing++-- | Create a 'PatchMapWithPatchingMove' that inserts everything in the given 'Map'+patchMapWithPatchingMoveInsertAll+ :: Map k (PatchTarget p) -> PatchMapWithPatchingMove k p+patchMapWithPatchingMoveInsertAll m = PatchMapWithPatchingMove $ flip fmap m $ \v -> NodeInfo+ { _nodeInfo_from = From_Insert v+ , _nodeInfo_to = Nothing+ }++-- | Make a @'PatchMapWithPatchingMove' k p@ which has the effect of inserting or replacing a value @v@ at the given key @k@, like 'Map.insert'.+insertMapKey+ :: k -> PatchTarget p -> PatchMapWithPatchingMove k p+insertMapKey k v = PatchMapWithPatchingMove . Map.singleton k $ NodeInfo (From_Insert v) Nothing++-- |Make a @'PatchMapWithPatchingMove' k p@ which has the effect of moving the value from the first key @k@ to the second key @k@, equivalent to:+--+-- @+-- 'Map.delete' src (maybe map ('Map.insert' dst) (Map.lookup src map))+-- @+moveMapKey+ :: ( DecidablyEmpty p+#if !MIN_VERSION_base(4,11,0)+ , Semigroup p+#endif+ , Patch p+ )+ => Ord k => k -> k -> PatchMapWithPatchingMove k p+moveMapKey src dst+ | src == dst = mempty+ | otherwise =+ PatchMapWithPatchingMove $ Map.fromList+ [ (dst, NodeInfo (From_Move src mempty) Nothing)+ , (src, NodeInfo From_Delete (Just dst))+ ]++-- |Make a @'PatchMapWithPatchingMove' k p@ which has the effect of swapping two keys in the mapping, equivalent to:+--+-- @+-- let aMay = Map.lookup a map+-- bMay = Map.lookup b map+-- in maybe id (Map.insert a) (bMay `mplus` aMay)+-- . maybe id (Map.insert b) (aMay `mplus` bMay)+-- . Map.delete a . Map.delete b $ map+-- @+swapMapKey+ :: ( DecidablyEmpty p+#if !MIN_VERSION_base(4,11,0)+ , Semigroup p+#endif+ , Patch p+ )+ => Ord k => k -> k -> PatchMapWithPatchingMove k p+swapMapKey src dst+ | src == dst = mempty+ | otherwise =+ PatchMapWithPatchingMove $ Map.fromList+ [ (dst, NodeInfo (From_Move src mempty) (Just src))+ , (src, NodeInfo (From_Move dst mempty) (Just dst))+ ]++-- | Make a @'PatchMapWithPatchingMove' k v@ which has the effect of deleting a key in+-- the mapping, equivalent to 'Map.delete'.+deleteMapKey+ :: k -> PatchMapWithPatchingMove k v+deleteMapKey k = PatchMapWithPatchingMove . Map.singleton k $ NodeInfo From_Delete Nothing++-- | Wrap a @'Map' k (NodeInfo k v)@ representing patch changes into a @'PatchMapWithPatchingMove' k v@, without checking any invariants.+--+-- __Warning:__ when using this function, you must ensure that the invariants of 'PatchMapWithPatchingMove' are preserved; they will not be checked.+unsafePatchMapWithPatchingMove+ :: Map k (NodeInfo k p) -> PatchMapWithPatchingMove k p+unsafePatchMapWithPatchingMove = PatchMapWithPatchingMove++-- | Apply the insertions, deletions, and moves to a given 'Map'+instance (Ord k, Patch p) => Patch (PatchMapWithPatchingMove k p) where+ type PatchTarget (PatchMapWithPatchingMove k p) = Map k (PatchTarget p)+ -- 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?+ apply (PatchMapWithPatchingMove m) old = Just $! insertions `Map.union` (old `Map.difference` deletions)+ where insertions = flip Map.mapMaybeWithKey m $ \_ ni -> case _nodeInfo_from ni of+ From_Insert v -> Just v+ From_Move k p -> applyAlways p <$> Map.lookup k old+ From_Delete -> Nothing+ deletions = flip Map.mapMaybeWithKey m $ \_ ni -> case _nodeInfo_from ni of+ From_Delete -> Just ()+ _ -> Nothing++-- | Returns all the new elements that will be added to the 'Map'+patchMapWithPatchingMoveNewElements+ :: PatchMapWithPatchingMove k p -> [PatchTarget p]+patchMapWithPatchingMoveNewElements = Map.elems . patchMapWithPatchingMoveNewElementsMap++-- | Return a @'Map' k v@ with all the inserts/updates from the given @'PatchMapWithPatchingMove' k v@.+patchMapWithPatchingMoveNewElementsMap+ :: PatchMapWithPatchingMove k p -> Map k (PatchTarget p)+patchMapWithPatchingMoveNewElementsMap (PatchMapWithPatchingMove p) = Map.mapMaybe f p+ where f ni = case _nodeInfo_from ni of+ From_Insert v -> Just v+ From_Move _ _ -> Nothing+ From_Delete -> Nothing++-- | Create a 'PatchMapWithPatchingMove' that, if applied to the given 'Map', will sort+-- its values using the given ordering function. The set keys of the 'Map' is+-- not changed.+patchThatSortsMapWith+ :: (Ord k, Monoid p)+ => (PatchTarget p -> PatchTarget p -> Ordering)+ -> Map k (PatchTarget p) -> PatchMapWithPatchingMove k p+patchThatSortsMapWith cmp m = PatchMapWithPatchingMove $ Map.fromList $ catMaybes $ zipWith g unsorted sorted+ where unsorted = Map.toList m+ sorted = sortBy (cmp `on` snd) unsorted+ f (to, _) (from, _) = if to == from then Nothing else+ Just (from, to)+ reverseMapping = Map.fromList $ catMaybes $ zipWith f unsorted sorted+ g (to, _) (from, _) = if to == from then Nothing else+ let Just movingTo = Map.lookup from reverseMapping+ in Just (to, NodeInfo (From_Move from mempty) $ Just movingTo)++-- | Create a 'PatchMapWithPatchingMove' that, if applied to the first 'Map' provided,+-- will produce a 'Map' with the same values as the second 'Map' but with the+-- values sorted with the given ordering function.+patchThatChangesAndSortsMapWith+ :: forall k p. (Ord k, Ord (PatchTarget p), Monoid p)+ => (PatchTarget p -> PatchTarget p -> Ordering)+ -> Map k (PatchTarget p) -> Map k (PatchTarget p) -> PatchMapWithPatchingMove k p+patchThatChangesAndSortsMapWith cmp oldByIndex newByIndexUnsorted = patchThatChangesMap oldByIndex newByIndex+ where newList = Map.toList newByIndexUnsorted+ newByIndex = Map.fromList $ zip (fst <$> newList) $ sortBy cmp $ snd <$> newList++-- | Create a 'PatchMapWithPatchingMove' that, if applied to the first 'Map' provided,+-- will produce the second 'Map'.+patchThatChangesMap+ :: (Ord k, Ord (PatchTarget p), Monoid p)+ => Map k (PatchTarget p) -> Map k (PatchTarget p) -> PatchMapWithPatchingMove k p+patchThatChangesMap oldByIndex newByIndex = patch+ where oldByValue = Map.fromListWith Set.union $ swap . first Set.singleton <$> Map.toList oldByIndex+ (insertsAndMoves, unusedValuesByValue) = flip runState oldByValue $ do+ let f k v = do+ remainingValues <- get+ let putRemainingKeys remainingKeys = put $ if Set.null remainingKeys+ then Map.delete v remainingValues+ else Map.insert v remainingKeys remainingValues+ case Map.lookup v remainingValues of+ Nothing -> return $ NodeInfo (From_Insert v) $ Just undefined -- There's no existing value we can take+ Just fromKs ->+ if k `Set.member` fromKs+ then do+ putRemainingKeys $ Set.delete k fromKs+ return $ NodeInfo (From_Move k mempty) $ Just undefined -- There's an existing value, and it's here, so no patch necessary+ else do+ (fromK, remainingKeys) <- return . fromJust $ Set.minView fromKs -- There's an existing value, but it's not here; move it here+ putRemainingKeys remainingKeys+ return $ NodeInfo (From_Move fromK mempty) $ Just undefined+ Map.traverseWithKey f newByIndex+ unusedOldKeys = fold unusedValuesByValue+ pointlessMove k = \case+ From_Move k' _ | k == k' -> True+ _ -> False+ keyWasMoved k = if k `Map.member` oldByIndex && not (k `Set.member` unusedOldKeys)+ then Just undefined+ else Nothing+ patch = unsafePatchMapWithPatchingMove $ Map.filterWithKey (\k -> not . pointlessMove k . _nodeInfo_from) $ Map.mergeWithKey (\k a _ -> Just $ nodeInfoSetTo (keyWasMoved k) a) (Map.mapWithKey $ \k -> nodeInfoSetTo $ keyWasMoved k) (Map.mapWithKey $ \k _ -> NodeInfo From_Delete $ keyWasMoved k) insertsAndMoves oldByIndex++-- | Change the 'From' value of a 'NodeInfo'+nodeInfoMapFrom+ :: (From k v -> From k v) -> NodeInfo k v -> NodeInfo k v+nodeInfoMapFrom f ni = ni { _nodeInfo_from = f $ _nodeInfo_from ni }++-- | Change the 'From' value of a 'NodeInfo', using a 'Functor' (or+-- 'Applicative', 'Monad', etc.) action to get the new value+nodeInfoMapMFrom+ :: Functor f => (From k v -> f (From k v)) -> NodeInfo k v -> f (NodeInfo k v)+nodeInfoMapMFrom f ni = fmap (\result -> ni { _nodeInfo_from = result }) $ f $ _nodeInfo_from ni++-- | Set the 'To' field of a 'NodeInfo'+nodeInfoSetTo+ :: To k -> NodeInfo k v -> NodeInfo k v+nodeInfoSetTo to ni = ni { _nodeInfo_to = to }++-- | Helper data structure used for composing patches using the monoid instance.+data Fixup k v+ = Fixup_Delete+ | Fixup_Update (These (From k v) (To k))++-- | Compose patches having the same effect as applying the patches in turn:+-- @'applyAlways' (p <> q) == 'applyAlways' p . 'applyAlways' q@+instance ( Ord k+#if !MIN_VERSION_base(4,11,0)+ , Semigroup p+#endif+ , DecidablyEmpty p+ , Patch p+ ) => Semigroup (PatchMapWithPatchingMove k p) where+ PatchMapWithPatchingMove ma <> PatchMapWithPatchingMove mb = PatchMapWithPatchingMove m+ where+ connections = Map.toList $ Map.intersectionWithKey (\_ a b -> (_nodeInfo_to a, _nodeInfo_from b)) ma mb+ h :: (k, (Maybe k, From k p)) -> [(k, Fixup k p)]+ h (_, (mToAfter, editBefore)) = case (mToAfter, editBefore) of+ (Just toAfter, From_Move fromBefore p)+ | fromBefore == toAfter && isEmpty p+ -> [(toAfter, Fixup_Delete)]+ | otherwise+ -> [ (toAfter, Fixup_Update (This editBefore))+ , (fromBefore, Fixup_Update (That mToAfter))+ ]+ (Nothing, From_Move fromBefore _) -> [(fromBefore, Fixup_Update (That mToAfter))] -- The item is destroyed in the second patch, so indicate that it is destroyed in the source map+ (Just toAfter, _) -> [(toAfter, Fixup_Update (This editBefore))]+ (Nothing, _) -> []+ mergeFixups _ Fixup_Delete Fixup_Delete = Fixup_Delete+ mergeFixups _ (Fixup_Update a) (Fixup_Update b)+ | This x <- a, That y <- b+ = Fixup_Update $ These x y+ | That y <- a, This x <- b+ = Fixup_Update $ These x y+ mergeFixups _ _ _ = error "PatchMapWithPatchingMove: incompatible fixups"+ fixups = Map.fromListWithKey mergeFixups $ concatMap h connections+ combineNodeInfos _ nia nib = NodeInfo+ { _nodeInfo_from = _nodeInfo_from nia+ , _nodeInfo_to = _nodeInfo_to nib+ }+ applyFixup _ ni = \case+ Fixup_Delete -> Nothing+ Fixup_Update u -> Just $ NodeInfo+ { _nodeInfo_from = case _nodeInfo_from ni of+ f@(From_Move _ p') -> case getHere u of -- The `from` fixup comes from the "old" patch+ Nothing -> f -- If there's no `from` fixup, just use the "new" `from`+ Just (From_Insert v) -> From_Insert $ applyAlways p' v+ Just From_Delete -> From_Delete+ Just (From_Move oldKey p) -> From_Move oldKey $ p' <> p+ _ -> error "PatchMapWithPatchingMove: fixup for non-move From"+ , _nodeInfo_to = fromMaybe (_nodeInfo_to ni) $ getThere u+ }+ m = Map.differenceWithKey applyFixup (Map.unionWithKey combineNodeInfos ma mb) fixups+ getHere :: These a b -> Maybe a+ getHere = \case+ This a -> Just a+ These a _ -> Just a+ That _ -> Nothing+ getThere :: These a b -> Maybe b+ getThere = \case+ This _ -> Nothing+ These _ b -> Just b+ That b -> Just b++--TODO: Figure out how to implement this in terms of PatchDMapWithPatchingMove rather than duplicating it here+-- | Compose patches having the same effect as applying the patches in turn:+-- @'applyAlways' (p <> q) == 'applyAlways' p . 'applyAlways' q@+instance ( Ord k+#if !MIN_VERSION_base(4,11,0)+ , Semigroup p+#endif+ , DecidablyEmpty p+ , Patch p+ ) => Monoid (PatchMapWithPatchingMove k p) where+ mempty = PatchMapWithPatchingMove mempty+ mappend = (<>)++makeWrapped ''PatchMapWithPatchingMove