on cd32efc help sign in
patch/src/Data/Patch/Class.hs
43 lines 1.6 kB history raw
1{-# LANGUAGE CPP #-}
2{-# LANGUAGE TypeFamilies #-}
3-- | The interface for types which represent changes made to other types
4module Data.Patch.Class where
6import Data.Functor.Identity
7import Data.Maybe
8#if !MIN_VERSION_base(4,11,0)
9import Data.Semigroup (Semigroup(..))
10#endif
11import Data.Proxy
13-- | A 'Patch' type represents a kind of change made to a datastructure.
14--
15-- If an instance of 'Patch' is also an instance of 'Semigroup', it should obey
16-- the law that @applyAlways (f <> g) == applyAlways f . applyAlways g@.
17class Patch p where
18 type PatchTarget p :: *
19 -- | Apply the patch @p a@ to the value @a@. If no change is needed, return
20 -- 'Nothing'.
21 apply :: p -> PatchTarget p -> Maybe (PatchTarget p)
23-- | Apply a 'Patch'; if it does nothing, return the original value
24applyAlways :: Patch p => p -> PatchTarget p -> PatchTarget p
25applyAlways p t = fromMaybe t $ apply p t
27-- | 'Identity' can be used as a 'Patch' that always fully replaces the value
28instance Patch (Identity a) where
29 type PatchTarget (Identity a) = a
30 apply (Identity a) _ = Just a
32-- | 'Proxy' can be used as a 'Patch' that does nothing.
33instance Patch (Proxy a) where
34 type PatchTarget (Proxy a) = a
35 apply ~Proxy _ = Nothing
37-- | Like '(.)', but composes functions that return patches rather than
38-- functions that return new values. The Semigroup instance for patches must
39-- apply patches right-to-left, like '(.)'.
40composePatchFunctions :: (Patch p, Semigroup p) => (PatchTarget p -> p) -> (PatchTarget p -> p) -> PatchTarget p -> p
41composePatchFunctions g f a =
42 let fp = f a
43 in g (applyAlways fp a) <> fp