on develop help sign in
Merge remote-tracking branch 'origin/develop' into patch-map-inner-patch
0dfcb56John Ericson
.travis.yml+3−5
@@ -139,12 +139,12 @@ script:
139 - cd ${DISTDIR} || false
139 - cd ${DISTDIR} || false
140 - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
140 - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
141 - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm '{}' \;
141 - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm '{}' \;
142− - PKGDIR_reflex="$(find . -maxdepth 1 -type d -regex '.*/reflex-[0-9.]*')"
142+ - PKGDIR_patch="$(find . -maxdepth 1 -type d -regex '.*/patch-[0-9.]*')"
143 # Generate cabal.project
143 # Generate cabal.project
144 - rm -rf cabal.project cabal.project.local cabal.project.freeze
144 - rm -rf cabal.project cabal.project.local cabal.project.freeze
145 - touch cabal.project
145 - touch cabal.project
146 - |
146 - |
147− echo "packages: ${PKGDIR_reflex}" >> cabal.project
147+ echo "packages: ${PKGDIR_patch}" >> cabal.project
148 - |
148 - |
149 - cat cabal.project || true
149 - cat cabal.project || true
150 - cat cabal.project.local || true
150 - cat cabal.project.local || true
@@ -157,13 +157,11 @@ script:
157 # Testing...
157 # Testing...
158 - if ! $GHCJS ; then ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all | color_cabal_output ; fi
158 - if ! $GHCJS ; then ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all | color_cabal_output ; fi
159 # cabal check...
159 # cabal check...
160− - (cd ${PKGDIR_reflex} && ${CABAL} -vnormal check)
160+ - (cd ${PKGDIR_patch} && ${CABAL} -vnormal check)
161 # haddock...
161 # haddock...
162 - if ! $GHCJS ; then ${CABAL} v2-haddock $WITHCOMPILER ${TEST} ${BENCH} all | color_cabal_output ; fi
162 - if ! $GHCJS ; then ${CABAL} v2-haddock $WITHCOMPILER ${TEST} ${BENCH} all | color_cabal_output ; fi
163 # Constraint sets
163 # Constraint sets
164 - rm -rf cabal.project.local
164 - rm -rf cabal.project.local
165− # Constraint set no-th
166− - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --constraint='reflex -use-template-haskell' all | color_cabal_output
167 # Constraint set old-these
165 # Constraint set old-these
168 - if $GHCJS || ! $GHCJS && [ $HCNUMVER -lt 80800 ] ; then ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --constraint='these <1' all | color_cabal_output ; fi
166 - if $GHCJS || ! $GHCJS && [ $HCNUMVER -lt 80800 ] ; then ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --constraint='these <1' all | color_cabal_output ; fi
169 # Constraint set old-witherable
167 # Constraint set old-witherable
ChangeLog.md+6
@@ -4,6 +4,12 @@
4
4
5* `PatchMapWithMove` supports moves with a patch.
5* `PatchMapWithMove` supports moves with a patch.
6
6
7+## 0.0.1.0
8+
9+* Support older GHCs with `split-these` flag.
10+
11+* Additional instances for the `Group` class for basic types.
12+
7## 0.0.0.1
13## 0.0.0.1
8
14
9* Remove unneeded dependencies
15* Remove unneeded dependencies
README.md+47
@@ -1,3 +1,50 @@
1## Patch
1## Patch
2
2
3Infrastructure for writing patches which act on other types.
3Infrastructure for writing patches which act on other types.
4+
5+A `Patch` type represents a kind of change made to a datastructure.
6+
7+```haskell
8+class Patch p where
9+ type PatchTarget p :: *
10+ -- | Apply the patch p a to the value a. If no change is needed, return
11+ -- 'Nothing'.
12+ apply :: p -> PatchTarget p -> Maybe (PatchTarget p)
13+```
14+
15+### Patching Maps
16+For example, `Data.Patch.Map` defines the `PatchMap` type which can be used to patch `Map`s. A `PatchMap` represents updates to a `Map` that can insert, remove, or replace items in the `Map`. In this example, the `Map` is the `PatchTarget` and the `PatchMap` is the `Patch`. Keep in mind that there are many other possible `Patch`es that can be applied to a `Map` (i.e., `Map` can be the `PatchTarget` for many different `Patch` instances).
17+
18+`PatchMap` is defined as:
19+
20+```haskell
21+newtype PatchMap k v = PatchMap { unPatchMap :: Map k (Maybe v) }
22+```
23+
24+The `Maybe` around the value is used to represent insertion/updates or deletion of the element at a given key.
25+
26+Its `Patch` instance begins with:
27+
28+```haskell
29+instance Ord k => Patch (PatchMap k v) where
30+ type PatchTarget (PatchMap k v) = Map k v
31+ ...
32+```
33+
34+When a `PatchMap` is applied to its `PatchTarget`, the following changes can occur:
35+
36+- If the key is present in the `Patch` and the `PatchTarget`...
37+
38+ - And the `Patch` value at that key is `Nothing`: delete that key from the `PatchTarget`.
39+
40+ - And the `Patch` value at that key is `Just x`: update the value at that key in the `PatchTarget` to `x`.
41+
42+- If the key is present in the `Patch` and not present in the `PatchTarget`...
43+
44+ - And the `Patch` value at that key is `Nothing`: do nothing because we're trying to delete a key that doesn't exist in the target in the first place.
45+
46+ - And the `Patch` value at that key is `Just x`: insert the key and the value `x` into the `PatchTarget`
47+
48+- If the key is *not* present in the `Patch` but present in the `PatchTarget`: do nothing.
49+
50+There are, of course, more complicated ways of patching maps involving, for example, moving values from one key to another. You can find the code for that in `Data.Patch.PatchMapWithMove`. Note that the `PatchTarget` type associated with the `PatchMapWithMove` patch instance is still `Map k v`!
cabal.haskell-ci+7
@@ -5,3 +5,10 @@ installed: -all
5
5
6-- https://github.com/haskell/cabal/issues/6106
6-- https://github.com/haskell/cabal/issues/6106
7install-dependencies: False
7install-dependencies: False
8+
9+constraint-set old-these
10+ ghc: <8.8
11+ constraints: these <1
12+
13+constraint-set old-witherable
14+ constraints: witherable <0.3.2
patch.cabal+14−4
@@ -1,5 +1,5 @@
1Name: patch
1Name: patch
2−Version: 0.0.0.1
2+Version: 0.0.1.0
3Synopsis: Infrastructure for writing patches which act on other types.
3Synopsis: Infrastructure for writing patches which act on other types.
4Description:
4Description:
5 In this library, a patch is something which can be applied, analogous to a
5 In this library, a patch is something which can be applied, analogous to a
@@ -23,6 +23,11 @@ tested-with:
23 GHC ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.1
23 GHC ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.1
24 GHCJS ==8.4
24 GHCJS ==8.4
25
25
26+flag split-these
27+ description: Use split these/semialign packages
28+ manual: False
29+ default: True
30+
26library
31library
27 hs-source-dirs: src
32 hs-source-dirs: src
28 build-depends: base >= 4.9 && < 4.14
33 build-depends: base >= 4.9 && < 4.14
@@ -30,10 +35,7 @@ library
30 , containers >= 0.6 && < 0.7
35 , containers >= 0.6 && < 0.7
31 , dependent-map >= 0.3 && < 0.4
36 , dependent-map >= 0.3 && < 0.4
32 , dependent-sum >= 0.6 && < 0.7
37 , dependent-sum >= 0.6 && < 0.7
33− , monoidal-containers >= 0.6 && < 0.7
34− , semialign >=1 && <1.2
35 , semigroupoids >= 4.0 && < 6
38 , semigroupoids >= 4.0 && < 6
36− , these >= 1 && <1.1
37 , transformers >= 0.5.6.0 && < 0.6
39 , transformers >= 0.5.6.0 && < 0.6
38 , witherable >= 0.3 && < 0.3.2
40 , witherable >= 0.3 && < 0.3.2
39
41
@@ -48,6 +50,14 @@ library
48
50
49 ghc-options: -Wall -fwarn-redundant-constraints -fwarn-tabs
51 ghc-options: -Wall -fwarn-redundant-constraints -fwarn-tabs
50
52
53+ if flag(split-these)
54+ build-depends: these >= 1 && <1.1
55+ , semialign >=1 && <1.2
56+ , monoidal-containers >= 0.6 && < 0.7
57+ else
58+ build-depends: these >= 0.4 && <0.9
59+ , monoidal-containers == 0.4.0.0
60+
51test-suite hlint
61test-suite hlint
52 type: exitcode-stdio-1.0
62 type: exitcode-stdio-1.0
53 main-is: hlint.hs
63 main-is: hlint.hs
release.nix+1
@@ -22,6 +22,7 @@ let
22 "release.nix"
22 "release.nix"
23 ".git"
23 ".git"
24 "dist"
24 "dist"
25+ "dist-newstyle"
25 "cabal.haskell-ci"
26 "cabal.haskell-ci"
26 "cabal.project"
27 "cabal.project"
27 ".travis.yml"
28 ".travis.yml"
src/Data/Patch.hs+56
@@ -1,4 +1,8 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3+{-# LANGUAGE StandaloneDeriving #-}
1{-# LANGUAGE TypeFamilies #-}
4{-# LANGUAGE TypeFamilies #-}
5+{-# LANGUAGE TypeOperators #-}
2-- |
6-- |
3-- Module:
7-- Module:
4-- Data.Patch
8-- Data.Patch
@@ -10,7 +14,9 @@ module Data.Patch
10 ) where
14 ) where
11
15
12import Data.Map.Monoidal (MonoidalMap)
16import Data.Map.Monoidal (MonoidalMap)
17+#if !MIN_VERSION_base(4,9,0)
13import Data.Semigroup (Semigroup (..), (<>))
18import Data.Semigroup (Semigroup (..), (<>))
19+#endif
14
20
15import Data.Patch.Class as X
21import Data.Patch.Class as X
16import Data.Patch.DMap as X hiding (getDeletions)
22import Data.Patch.DMap as X hiding (getDeletions)
@@ -23,6 +29,11 @@ import Data.Patch.Map as X
23import Data.Patch.MapWithMove as X (PatchMapWithMove, patchMapWithMoveNewElements,
29import Data.Patch.MapWithMove as X (PatchMapWithMove, patchMapWithMoveNewElements,
24 patchMapWithMoveNewElementsMap, unPatchMapWithMove,
30 patchMapWithMoveNewElementsMap, unPatchMapWithMove,
25 unsafePatchMapWithMove)
31 unsafePatchMapWithMove)
32+import GHC.Generics
33+import Data.Functor.Identity
34+import Data.Functor.Const
35+import Data.Proxy
36+import Control.Applicative
26
37
27-- | A 'Group' is a 'Monoid' where every element has an inverse.
38-- | A 'Group' is a 'Monoid' where every element has an inverse.
28class (Semigroup q, Monoid q) => Group q where
39class (Semigroup q, Monoid q) => Group q where
@@ -44,3 +55,48 @@ instance (Ord k, Group q) => Group (MonoidalMap k q) where
44 negateG = fmap negateG
55 negateG = fmap negateG
45
56
46instance (Ord k, Additive q) => Additive (MonoidalMap k q)
57instance (Ord k, Additive q) => Additive (MonoidalMap k q)
58+
59+-- | Trivial group.
60+instance Group () where
61+ negateG _ = ()
62+ _ ~~ _ = ()
63+instance Additive ()
64+
65+-- | Product group. A Pair of groups gives rise to a group
66+instance (Group a, Group b) => Group (a, b) where
67+ negateG (a, b) = (negateG a, negateG b)
68+ (a, b) ~~ (c, d) = (a ~~ c, b ~~ d)
69+instance (Additive a, Additive b) => Additive (a, b)
70+
71+-- See https://gitlab.haskell.org/ghc/ghc/issues/11135#note_111802 for the reason Compose is not also provided.
72+-- Base does not define Monoid (Compose f g a) so this is the best we can
73+-- really do for functor composition.
74+instance Group (f (g a)) => Group ((f :.: g) a) where
75+ negateG (Comp1 xs) = Comp1 (negateG xs)
76+ Comp1 xs ~~ Comp1 ys = Comp1 (xs ~~ ys)
77+instance Additive (f (g a)) => Additive ((f :.: g) a)
78+
79+-- | Product of groups, Functor style.
80+instance (Group (f a), Group (g a)) => Group ((f :*: g) a) where
81+ negateG (a :*: b) = negateG a :*: negateG b
82+ (a :*: b) ~~ (c :*: d) = (a ~~ c) :*: (b ~~ d)
83+instance (Additive (f a), Additive (g a)) => Additive ((f :*: g) a)
84+
85+-- | Trivial group, Functor style
86+instance Group (Proxy x) where
87+ negateG _ = Proxy
88+ _ ~~ _ = Proxy
89+instance Additive (Proxy x)
90+
91+-- | Const lifts groups into a functor.
92+deriving instance Group a => Group (Const a x)
93+instance Additive a => Additive (Const a x)
94+-- | Ideitnty lifts groups pointwise (at only one point)
95+deriving instance Group a => Group (Identity a)
96+instance Additive a => Additive (Identity a)
97+
98+-- | Functions lift groups pointwise.
99+instance Group b => Group (a -> b) where
100+ negateG f = negateG . f
101+ (~~) = liftA2 (~~)
102+instance Additive b => Additive (a -> b)
src/Data/Patch/Class.hs+6
@@ -5,6 +5,7 @@ module Data.Patch.Class where
5import Data.Functor.Identity
5import Data.Functor.Identity
6import Data.Maybe
6import Data.Maybe
7import Data.Semigroup (Semigroup(..))
7import Data.Semigroup (Semigroup(..))
8+import Data.Proxy
8
9
9-- | A 'Patch' type represents a kind of change made to a datastructure.
10-- | A 'Patch' type represents a kind of change made to a datastructure.
10--
11--
@@ -25,6 +26,11 @@ instance Patch (Identity a) where
25 type PatchTarget (Identity a) = a
26 type PatchTarget (Identity a) = a
26 apply (Identity a) _ = Just a
27 apply (Identity a) _ = Just a
27
28
29+-- | 'Identity' can be used as a 'Patch' that always fully replaces the value
30+instance Patch (Proxy a) where
31+ type PatchTarget (Proxy a) = a
32+ apply ~Proxy _ = Nothing
33+
28-- | Like '(.)', but composes functions that return patches rather than
34-- | Like '(.)', but composes functions that return patches rather than
29-- functions that return new values. The Semigroup instance for patches must
35-- functions that return new values. The Semigroup instance for patches must
30-- apply patches right-to-left, like '(.)'.
36-- apply patches right-to-left, like '(.)'.
src/Data/Patch/DMapWithMove.hs+10−9
@@ -31,6 +31,7 @@ import qualified Data.Map as Map
31import Data.Maybe
31import Data.Maybe
32import Data.Semigroup (Semigroup (..), (<>))
32import Data.Semigroup (Semigroup (..), (<>))
33import Data.Some (Some(Some))
33import Data.Some (Some(Some))
34+import Data.Proxy
34import Data.These
35import Data.These
35
36
36-- | Like 'PatchMapWithMove', but for 'DMap'. Each key carries a 'NodeInfo' which describes how it will be changed by the patch and connects move sources and
37-- | Like 'PatchMapWithMove', but for 'DMap'. Each key carries a 'NodeInfo' which describes how it will be changed by the patch and connects move sources and
@@ -303,41 +304,41 @@ nodeInfoMapFromM f ni = fmap (\result -> ni { _nodeInfo_from = result }) $ f $ _
303
304
304-- |Weaken a 'PatchDMapWithMove' to a 'PatchMapWithMove' by weakening the keys from @k a@ to @'Some' k@ and applying a given weakening function @v a -> v'@ to
305-- |Weaken a 'PatchDMapWithMove' to a 'PatchMapWithMove' by weakening the keys from @k a@ to @'Some' k@ and applying a given weakening function @v a -> v'@ to
305-- values.
306-- values.
306−weakenPatchDMapWithMoveWith :: forall k v v'. (forall a. v a -> v') -> PatchDMapWithMove k v -> PatchMapWithMove (Some k) v'
307+weakenPatchDMapWithMoveWith :: forall k v v'. (forall a. v a -> v') -> PatchDMapWithMove k v -> PatchMapWithMove (Some k) (Proxy v')
307weakenPatchDMapWithMoveWith f (PatchDMapWithMove p) = PatchMapWithMove $ weakenDMapWith g p
308weakenPatchDMapWithMoveWith f (PatchDMapWithMove p) = PatchMapWithMove $ weakenDMapWith g p
308− where g :: forall a. NodeInfo k v a -> MapWithMove.NodeInfo (Some k) v'
309+ where g :: forall a. NodeInfo k v a -> MapWithMove.NodeInfo (Some k) (Proxy v')
309 g ni = MapWithMove.NodeInfo
310 g ni = MapWithMove.NodeInfo
310 { MapWithMove._nodeInfo_from = case _nodeInfo_from ni of
311 { MapWithMove._nodeInfo_from = case _nodeInfo_from ni of
311 From_Insert v -> MapWithMove.From_Insert $ f v
312 From_Insert v -> MapWithMove.From_Insert $ f v
312 From_Delete -> MapWithMove.From_Delete
313 From_Delete -> MapWithMove.From_Delete
313− From_Move k -> MapWithMove.From_Move $ Some k
314+ From_Move k -> MapWithMove.From_Move (Some k) Proxy
314 , MapWithMove._nodeInfo_to = Some <$> getComposeMaybe (_nodeInfo_to ni)
315 , MapWithMove._nodeInfo_to = Some <$> getComposeMaybe (_nodeInfo_to ni)
315 }
316 }
316
317
317-- |"Weaken" a @'PatchDMapWithMove' (Const2 k a) v@ to a @'PatchMapWithMove' k v'@. Weaken is in scare quotes because the 'Const2' has already disabled any
318-- |"Weaken" a @'PatchDMapWithMove' (Const2 k a) v@ to a @'PatchMapWithMove' k v'@. Weaken is in scare quotes because the 'Const2' has already disabled any
318-- dependency in the typing and all points are already @a@, hence the function to map each value to @v'@ is not higher rank.
319-- dependency in the typing and all points are already @a@, hence the function to map each value to @v'@ is not higher rank.
319−patchDMapWithMoveToPatchMapWithMoveWith :: forall k v v' a. (v a -> v') -> PatchDMapWithMove (Const2 k a) v -> PatchMapWithMove k v'
320+patchDMapWithMoveToPatchMapWithMoveWith :: forall k v v' a. (v a -> v') -> PatchDMapWithMove (Const2 k a) v -> PatchMapWithMove k (Proxy v')
320patchDMapWithMoveToPatchMapWithMoveWith f (PatchDMapWithMove p) = PatchMapWithMove $ dmapToMapWith g p
321patchDMapWithMoveToPatchMapWithMoveWith f (PatchDMapWithMove p) = PatchMapWithMove $ dmapToMapWith g p
321− where g :: NodeInfo (Const2 k a) v a -> MapWithMove.NodeInfo k v'
322+ where g :: NodeInfo (Const2 k a) v a -> MapWithMove.NodeInfo k (Proxy v')
322 g ni = MapWithMove.NodeInfo
323 g ni = MapWithMove.NodeInfo
323 { MapWithMove._nodeInfo_from = case _nodeInfo_from ni of
324 { MapWithMove._nodeInfo_from = case _nodeInfo_from ni of
324 From_Insert v -> MapWithMove.From_Insert $ f v
325 From_Insert v -> MapWithMove.From_Insert $ f v
325 From_Delete -> MapWithMove.From_Delete
326 From_Delete -> MapWithMove.From_Delete
326− From_Move (Const2 k) -> MapWithMove.From_Move k
327+ From_Move (Const2 k) -> MapWithMove.From_Move k Proxy
327 , MapWithMove._nodeInfo_to = unConst2 <$> getComposeMaybe (_nodeInfo_to ni)
328 , MapWithMove._nodeInfo_to = unConst2 <$> getComposeMaybe (_nodeInfo_to ni)
328 }
329 }
329
330
330-- |"Strengthen" a @'PatchMapWithMove' k v@ into a @'PatchDMapWithMove ('Const2' k a)@; that is, turn a non-dependently-typed patch into a dependently typed
331-- |"Strengthen" a @'PatchMapWithMove' k v@ into a @'PatchDMapWithMove ('Const2' k a)@; that is, turn a non-dependently-typed patch into a dependently typed
331-- one but which always has a constant key type represented by 'Const2'. Apply the given function to each @v@ to produce a @v' a@.
332-- one but which always has a constant key type represented by 'Const2'. Apply the given function to each @v@ to produce a @v' a@.
332-- Completemented by 'patchDMapWithMoveToPatchMapWithMoveWith'
333-- Completemented by 'patchDMapWithMoveToPatchMapWithMoveWith'
333−const2PatchDMapWithMoveWith :: forall k v v' a. (v -> v' a) -> PatchMapWithMove k v -> PatchDMapWithMove (Const2 k a) v'
334+const2PatchDMapWithMoveWith :: forall k v v' a. (v -> v' a) -> PatchMapWithMove k (Proxy v) -> PatchDMapWithMove (Const2 k a) v'
334const2PatchDMapWithMoveWith f (PatchMapWithMove p) = PatchDMapWithMove $ DMap.fromDistinctAscList $ g <$> Map.toAscList p
335const2PatchDMapWithMoveWith f (PatchMapWithMove p) = PatchDMapWithMove $ DMap.fromDistinctAscList $ g <$> Map.toAscList p
335− where g :: (k, MapWithMove.NodeInfo k v) -> DSum (Const2 k a) (NodeInfo (Const2 k a) v')
336+ where g :: (k, MapWithMove.NodeInfo k (Proxy v)) -> DSum (Const2 k a) (NodeInfo (Const2 k a) v')
336 g (k, ni) = Const2 k :=> NodeInfo
337 g (k, ni) = Const2 k :=> NodeInfo
337 { _nodeInfo_from = case MapWithMove._nodeInfo_from ni of
338 { _nodeInfo_from = case MapWithMove._nodeInfo_from ni of
338 MapWithMove.From_Insert v -> From_Insert $ f v
339 MapWithMove.From_Insert v -> From_Insert $ f v
339 MapWithMove.From_Delete -> From_Delete
340 MapWithMove.From_Delete -> From_Delete
340− MapWithMove.From_Move fromKey -> From_Move $ Const2 fromKey
341+ MapWithMove.From_Move fromKey Proxy -> From_Move $ Const2 fromKey
341 , _nodeInfo_to = ComposeMaybe $ Const2 <$> MapWithMove._nodeInfo_to ni
342 , _nodeInfo_to = ComposeMaybe $ Const2 <$> MapWithMove._nodeInfo_to ni
342 }
343 }
343
344
src/Data/Patch/MapWithMove.hs+8−5
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
1{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE LambdaCase #-}
3{-# LANGUAGE LambdaCase #-}
3{-# LANGUAGE PatternGuards #-}
4{-# LANGUAGE PatternGuards #-}
@@ -7,25 +8,27 @@
7{-# LANGUAGE UndecidableInstances #-}
8{-# LANGUAGE UndecidableInstances #-}
8-- | 'Patch'es on 'Map' that can insert, delete, and move values from one key to
9-- | 'Patch'es on 'Map' that can insert, delete, and move values from one key to
9-- another
10-- another
10−module Reflex.Patch.MapWithMove where
11+module Data.Patch.MapWithMove where
11
12
12−import Reflex.Patch.Class
13+import Data.Patch.Class
13
14
14import Control.Arrow
15import Control.Arrow
15−import Control.Monad.State
16+import Control.Monad.Trans.State
16import Data.Foldable
17import Data.Foldable
17import Data.Function
18import Data.Function
18import Data.List
19import Data.List
19import Data.Map (Map)
20import Data.Map (Map)
20import qualified Data.Map as Map
21import qualified Data.Map as Map
21import Data.Maybe
22import Data.Maybe
23+#if !MIN_VERSION_base(4,9,0)
22import Data.Semigroup
24import Data.Semigroup
25+#endif
23import qualified Data.Set as Set
26import qualified Data.Set as Set
24import Data.These
27import Data.These
25import Data.Tuple
28import Data.Tuple
26
29
27−-- | Patch a DMap with additions, deletions, and moves. Invariant: If key @k1@
30+-- | Patch a Map with additions, deletions, and moves. Invariant: If key @k1@
28−-- is coming from @From_Move k@, then key @k2@ should be going to @Just k1@,
31+-- is coming from @From_Move k2@, then key @k2@ should be going to @Just k1@,
29-- and vice versa. There should never be any unpaired From/To keys.
32-- and vice versa. There should never be any unpaired From/To keys.
30newtype PatchMapWithMove k p = PatchMapWithMove (Map k (NodeInfo k p))
33newtype PatchMapWithMove k p = PatchMapWithMove (Map k (NodeInfo k p))
31deriving instance (Show k, Show p, Show (PatchTarget p)) => Show (PatchMapWithMove k p)
34deriving instance (Show k, Show p, Show (PatchTarget p)) => Show (PatchMapWithMove k p)