2{-# LANGUAGE DefaultSignatures #-}
3{-# LANGUAGE DerivingStrategies #-}
4{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE PolyKinds #-}
8{-# LANGUAGE ScopedTypeVariables #-}
9{-# LANGUAGE TypeFamilies #-}
10{-# LANGUAGE TypeOperators #-}
11-- | The interface for types which represent changes made to other types
12module Data.Patch.Class where
14import qualified Data.Semigroupoid as Cat
15import Data.Functor.Identity
16import Data.Functor.Misc
17import Data.Kind (Type)
19#if !MIN_VERSION_base(4,11,0)
20import Data.Semigroup (Semigroup(..))
23import Data.Type.Equality ((:~:) (..))
26 type PatchSource p :: Type
27 type PatchTarget p :: Type
28 -- | Apply the patch @p a@ to the value @a@. If no change is needed, return
33 -> Either (PatchSource p :~: PatchTarget p) (PatchTarget p)
38 -> Either (PatchSource p :~: PatchTarget p) (PatchTarget p)
39 applyHet p a = case apply p a of
43-- | Apply a 'PatchHet'; if it does nothing, return the original value
44applyAlwaysHet :: PatchHet p => p -> PatchSource p -> PatchTarget p
45applyAlwaysHet p t = case applyHet p t of
49-- | A 'Patch' type represents a kind of change made to a datastructure.
51-- If an instance of 'Patch' is also an instance of 'Semigroup', it should obey
52-- the law that @applyAlways (f <> g) == applyAlways f . applyAlways g@.
54 , PatchSource p ~ PatchTarget p
56 -- | Apply the patch @p a@ to the value @a@. If no change is needed, return
58 apply :: p -> PatchTarget p -> Maybe (PatchTarget p)
60-- | Apply a 'Patch'; if it does nothing, return the original value
61applyAlways :: Patch p => p -> PatchTarget p -> PatchTarget p
62applyAlways p t = fromMaybe t $ apply p t
64-- | 'Identity' can be used as a 'Patch' that always fully replaces the value
65instance PatchHet (Identity a) where
66 type PatchSource (Identity a) = a
67 type PatchTarget (Identity a) = a
68instance Patch (Identity a) where
69 apply (Identity a) _ = Just a
71-- | 'Proxy' can be used as a 'Patch' that does nothing.
72instance forall (a :: Type). PatchHet (Proxy a) where
73 type PatchSource (Proxy a) = a
74 type PatchTarget (Proxy a) = a
75instance forall (a :: Type). Patch (Proxy a) where
76 apply ~Proxy _ = Nothing
78-- | Like '(.)', but composes functions that return patches rather than
79-- functions that return new values. The Semigroup instance for patches must
80-- apply patches right-to-left, like '(.)'.
82 :: (Patch p, Semigroup p)
83 => (PatchTarget p -> p)
84 -> (PatchTarget p -> p)
86composePatchFunctions g f a =
88 in g (applyAlways fp a) <> fp
91class PatchHet2Base (p :: k -> k -> *) where
92 type PatchSource1 p :: k -> *
93 type PatchTarget1 p :: k -> *
95class ( PatchHet2Base p
96 , PatchHet (p from to)
97 , PatchSource1 p from ~ PatchSource (p from to)
98 , PatchTarget1 p to ~ PatchTarget (p from to)
99 ) => PatchHet2Locally (p :: k -> k -> *) from to where
100instance ( PatchHet2Base p
101 , PatchHet (p from to)
102 , PatchSource1 p from ~ PatchSource (p from to)
103 , PatchTarget1 p to ~ PatchTarget (p from to)
104 ) => PatchHet2Locally (p :: k -> k -> *) from to where
107 :: PatchHet2Locally p from to
109 -> PatchSource1 p from
110 -> Either (PatchSource1 p from :~: PatchTarget1 p to) (PatchTarget1 p to)
111applyHet2Locally = applyHet
113applyAlwaysHet2Locally
114 :: PatchHet2Locally p from to
116 -> PatchSource1 p from
118applyAlwaysHet2Locally = applyAlwaysHet
120-- TODO once we can use quantified constraints, perhaps combine PatchHet2Base and
121-- PatchHet2Locally, or at least get rid of this.
122class PatchHet2Base p => PatchHet2 (p :: k -> k -> *) where
125 -> PatchSource1 p from
126 -> Either (PatchSource1 p from :~: PatchTarget1 p to) (PatchTarget1 p to)
131 -> PatchSource1 p from
133applyAlwaysHet2 p t = case applyHet2 p t of
137-- | Connect the classes without quanitified constraints
138newtype ProjectLocal p from to = ProjectLocal { unProjectLocal :: p from to }
139 deriving newtype Cat.Semigroupoid
141instance PatchHet2 p => PatchHet (ProjectLocal p from to) where
142 type PatchSource (ProjectLocal p from to) = PatchSource1 p from
143 type PatchTarget (ProjectLocal p from to) = PatchTarget1 p to
144 applyHet (ProjectLocal p) = applyHet2 p
146instance PatchHet2 p => PatchHet2Base (ProjectLocal p) where
147 type PatchSource1 (ProjectLocal p) = PatchSource1 p
148 type PatchTarget1 (ProjectLocal p) = PatchTarget1 p
150class ( PatchHet2Base p
151 , PatchSource1 p ~ PatchTarget1 p
153instance ( PatchHet2Base p
154 , PatchSource1 p ~ PatchTarget1 p
157-- | 'First2' can be used as a 'Patch' that always fully replaces the value
158instance PatchHet (First2 (t :: k -> *) (from :: k) (to :: k)) where
159 type PatchSource (First2 t from to) = t from
160 type PatchTarget (First2 t from to) = t to
161 applyHet (First2 val) _ = Right val
163-- | 'Proxy3' can be used as a 'Patch' that always does nothing
164instance PatchHet (Proxy3 (t :: k -> *) (a :: k) (a :: k)) where
165 type PatchSource (Proxy3 t a a) = t a
166 type PatchTarget (Proxy3 t a a) = t a
167 applyHet ~Proxy3 _ = Left Refl
169instance PatchHet2Base (Proxy3 (t :: k -> *) :: k -> k -> *) where
170 type PatchSource1 (Proxy3 t) = t
171 type PatchTarget1 (Proxy3 t) = t
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list