@@ -1,4 +1,6 @@
1+{-# LANGUAGE DefaultSignatures #-}
1{-# LANGUAGE TypeFamilies #-}
2{-# LANGUAGE TypeFamilies #-}
3+{-# LANGUAGE TypeOperators #-}
2-- | The interface for types which represent changes made to other types
4-- | The interface for types which represent changes made to other types
3module Data.Patch.Class where
5module Data.Patch.Class where
@@ -6,13 +8,39 @@ import Data.Functor.Identity
6import Data.Maybe
8import Data.Maybe
7import Data.Semigroup (Semigroup(..))
9import Data.Semigroup (Semigroup(..))
8import Data.Proxy
10import Data.Proxy
11+import Data.Type.Equality ((:~:) (..))
13+class PatchHet p where
14+ type PatchSource p :: *
15+ type PatchTarget p :: *
16+ -- | Apply the patch @p a@ to the value @a@. If no change is needed, return
21+ -> Either (PatchSource p :~: PatchTarget p) (PatchTarget p)
26+ -> Either (PatchSource p :~: PatchTarget p) (PatchTarget p)
27+ applyHet p a = case apply p a of
31+-- | Apply a 'PatchHet'; if it does nothing, return the original value
32+applyAlwaysHet :: PatchHet p => p -> PatchSource p -> PatchTarget p
33+applyAlwaysHet p t = case applyHet p t of
10-- | A 'Patch' type represents a kind of change made to a datastructure.
37-- | A 'Patch' type represents a kind of change made to a datastructure.
12-- If an instance of 'Patch' is also an instance of 'Semigroup', it should obey
39-- If an instance of 'Patch' is also an instance of 'Semigroup', it should obey
13-- the law that @applyAlways (f <> g) == applyAlways f . applyAlways g@.
40-- the law that @applyAlways (f <> g) == applyAlways f . applyAlways g@.
42+ , PatchSource p ~ PatchTarget p
14−class Patch p where
43+ ) => Patch p where
15− type PatchTarget p :: *
16 -- | Apply the patch @p a@ to the value @a@. If no change is needed, return
44 -- | Apply the patch @p a@ to the value @a@. If no change is needed, return
17 -- 'Nothing'.
45 -- 'Nothing'.
18 apply :: p -> PatchTarget p -> Maybe (PatchTarget p)
46 apply :: p -> PatchTarget p -> Maybe (PatchTarget p)
@@ -22,19 +50,27 @@ applyAlways :: Patch p => p -> PatchTarget p -> PatchTarget p
22applyAlways p t = fromMaybe t $ apply p t
50applyAlways p t = fromMaybe t $ apply p t
24-- | 'Identity' can be used as a 'Patch' that always fully replaces the value
52-- | 'Identity' can be used as a 'Patch' that always fully replaces the value
25−instance Patch (Identity a) where
53+instance PatchHet (Identity a) where
54+ type PatchSource (Identity a) = a
26 type PatchTarget (Identity a) = a
55 type PatchTarget (Identity a) = a
56+instance Patch (Identity a) where
27 apply (Identity a) _ = Just a
57 apply (Identity a) _ = Just a
29-- | 'Identity' can be used as a 'Patch' that always fully replaces the value
59-- | 'Identity' can be used as a 'Patch' that always fully replaces the value
30−instance Patch (Proxy a) where
60+instance PatchHet (Proxy a) where
61+ type PatchSource (Proxy a) = a
31 type PatchTarget (Proxy a) = a
62 type PatchTarget (Proxy a) = a
63+instance Patch (Proxy a) where
32 apply ~Proxy _ = Nothing
64 apply ~Proxy _ = Nothing
34-- | Like '(.)', but composes functions that return patches rather than
66-- | Like '(.)', but composes functions that return patches rather than
35-- functions that return new values. The Semigroup instance for patches must
67-- functions that return new values. The Semigroup instance for patches must
36-- apply patches right-to-left, like '(.)'.
68-- apply patches right-to-left, like '(.)'.
37−composePatchFunctions :: (Patch p, Semigroup p) => (PatchTarget p -> p) -> (PatchTarget p -> p) -> PatchTarget p -> p
69+composePatchFunctions
70+ :: (Patch p, Semigroup p)
71+ => (PatchTarget p -> p)
72+ -> (PatchTarget p -> p)
73+ -> PatchTarget p -> p
38composePatchFunctions g f a =
74composePatchFunctions g f a =
39 let fp = f a
75 let fp = f a
40 in g (applyAlways fp a) <> fp
76 in g (applyAlways fp a) <> fp