1 -- For type class synonyms
2 {-# LANGUAGE ConstraintKinds #-}
4 {-# LANGUAGE DataKinds #-}
5 -- For adding LiftDerived* constraints
6 {-# LANGUAGE DefaultSignatures #-}
7 {-# LANGUAGE PolyKinds #-}
9 -- | This modules enables to give a default value to combinators
10 -- when it is possible to factorize the implementation of some combinators
11 -- for a given semantic.
12 module Symantic.Syntaxes.Derive where
14 import Data.Function ((.))
15 import Data.Kind (Type)
19 -- | The kind of @sem@(antics) throughout this library.
20 type Semantic = Type -> Type
22 -- * Type family 'Derived'
24 -- | The next 'Semantic' that @(sem)@ derives to.
25 type family Derived (sem :: Semantic) :: Semantic
27 -- * Class 'Derivable'
29 -- | Derive from a semantic @(sem)@
30 -- another semantic determined by the 'Derived' open type family.
31 -- This is mostly useful when running a semantic stack,
32 -- but also when going back from an initial encoding to a final one.
34 -- Note that 'derive' and 'liftDerived' are not necessarily reciprocical functions.
35 class Derivable sem where
36 derive :: sem a -> Derived sem a
38 -- * Class 'LiftDerived'
40 -- | Lift the 'Derived' interpreter of an interpreter, to that interpreter.
41 -- This is mostly useful to give default values to class methods
42 -- in order to skip their definition for interpreters
43 -- where 'liftDerived' can already apply the right semantic.
45 -- Note that 'derive' and 'liftDerived' are not necessarily reciprocical functions.
46 class LiftDerived sem where
47 liftDerived :: Derived sem a -> sem a
49 -- * Class 'LiftDerived1'
51 -- | Convenient wrapper of 'derive' and 'liftDerived' for functions with a single argument.
52 class LiftDerived1 sem where
54 (Derived sem a -> Derived sem b) ->
57 liftDerived1 f = liftDerived . f . derive
58 default liftDerived1 ::
61 (Derived sem a -> Derived sem b) ->
65 -- * Class 'LiftDerived2'
67 -- | Convenient wrapper of 'derive' and 'liftDerived' for functions with two arguments.
68 -- Note that the default instance relies upon 'LiftDerived', not 'LiftDerived1'.
69 class LiftDerived2 sem where
71 (Derived sem a -> Derived sem b -> Derived sem c) ->
75 liftDerived2 f a b = liftDerived (f (derive a) (derive b))
76 default liftDerived2 ::
79 (Derived sem a -> Derived sem b -> Derived sem c) ->
84 -- * Class 'LiftDerived3'
86 -- | Convenient wrapper of 'derive' and 'liftDerived' for functions with three arguments.
87 -- Note that the default instance relies upon 'LiftDerived', not 'LiftDerived2'.
88 class LiftDerived3 sem where
90 (Derived sem a -> Derived sem b -> Derived sem c -> Derived sem d) ->
95 liftDerived3 f a b c = liftDerived (f (derive a) (derive b) (derive c))
96 default liftDerived3 ::
99 (Derived sem a -> Derived sem b -> Derived sem c -> Derived sem d) ->
105 -- * Class 'LiftDerived4'
107 -- | Convenient wrapper of 'derive' and 'liftDerived' for functions with three arguments.
108 -- Note that the default instance relies upon 'LiftDerived', not 'LiftDerived3'.
109 class LiftDerived4 sem where
111 (Derived sem a -> Derived sem b -> Derived sem c -> Derived sem d -> Derived sem e) ->
117 liftDerived4 f a b c d = liftDerived (f (derive a) (derive b) (derive c) (derive d))
118 default liftDerived4 ::
121 (Derived sem a -> Derived sem b -> Derived sem c -> Derived sem d -> Derived sem e) ->
128 -- * Type synonyms @FromDerived*@
130 -- | Convenient type synonym for using 'liftDerived' on 'Syntax' @(syn)@.
131 type FromDerived syn sem = (LiftDerived sem, syn (Derived sem))
133 type FromDerived1 syn sem = (LiftDerived1 sem, syn (Derived sem))
134 type FromDerived2 syn sem = (LiftDerived2 sem, syn (Derived sem))
135 type FromDerived3 syn sem = (LiftDerived3 sem, syn (Derived sem))
136 type FromDerived4 syn sem = (LiftDerived4 sem, syn (Derived sem))