1 {-# LANGUAGE DataKinds #-} -- For ReprKind
2 {-# LANGUAGE PatternSynonyms #-} -- For (:!:)
3 {-# LANGUAGE TypeFamilyDependencies #-} -- For Permutation
4 {-# LANGUAGE UndecidableInstances #-} -- For Permutation
5 -- | Combinators in this module conflict with usual ones from the @Prelude@
6 -- hence they are meant to be imported either explicitely or qualified.
7 module Symantic.Classes where
9 import Data.Bool (Bool(..))
10 import Data.Char (Char)
11 import Data.Either (Either(..))
14 import Data.Kind (Type)
15 import Data.Maybe (Maybe(..), fromJust)
16 import Data.Proxy (Proxy(..))
17 import Data.Semigroup (Semigroup)
18 import Data.String (String)
19 import GHC.Generics (Generic)
20 import Numeric.Natural (Natural)
21 import qualified Control.Category as Cat
22 import qualified Data.Function as Fun
23 import qualified Data.Tuple as Tuple
25 import Symantic.Derive
27 import Symantic.CurryN
30 type Syntax = Semantic -> Constraint
32 -- ** Type family 'Syntaxes'
33 -- | Merge several 'Syntax'es into a single one.
35 -- Useful in 'IfSemantic'.
36 type family Syntaxes (syns :: [Syntax]) (sem :: Semantic) :: Constraint where
38 Syntaxes (syn ': syns) sem = (syn sem, Syntaxes syns sem)
41 -- | The kind of @sem@(antics) throughout this library.
42 type Semantic = Type -> Type
44 -- * Class 'Abstractable'
45 class Abstractable sem where
46 -- | Lambda term abstraction, in HOAS (Higher-Order Abstract Syntax) style.
47 lam :: (sem a -> sem b) -> sem (a->b)
48 -- | Like 'lam' but whose argument must be used only once,
49 -- hence safe to beta-reduce (inline) without duplicating work.
50 lam1 :: (sem a -> sem b) -> sem (a->b)
52 -- | Application, aka. unabstract.
53 (.@) :: sem (a->b) -> sem a -> sem b; infixl 9 .@
54 lam f = liftDerived (lam (derive Fun.. f Fun.. liftDerived))
55 lam1 f = liftDerived (lam1 (derive Fun.. f Fun.. liftDerived))
56 var = liftDerived1 var
57 (.@) = liftDerived2 (.@)
59 FromDerived Abstractable sem => Derivable sem =>
60 (sem a -> sem b) -> sem (a->b)
62 FromDerived Abstractable sem => Derivable sem =>
63 (sem a -> sem b) -> sem (a->b)
65 FromDerived1 Abstractable sem =>
68 FromDerived2 Abstractable sem =>
69 sem (a->b) -> sem a -> sem b
71 -- ** Class 'Functionable'
72 class Functionable sem where
73 const :: sem (a -> b -> a)
74 flip :: sem ((a -> b -> c) -> b -> a -> c)
76 (.) :: sem ((b->c) -> (a->b) -> a -> c); infixr 9 .
77 ($) :: sem ((a->b) -> a -> b); infixr 0 $
78 const = liftDerived const
79 flip = liftDerived flip
84 FromDerived Functionable sem =>
87 FromDerived Functionable sem =>
88 sem ((a -> b -> c) -> b -> a -> c)
90 FromDerived Functionable sem =>
93 FromDerived Functionable sem =>
94 sem ((b->c) -> (a->b) -> a -> c)
96 FromDerived Functionable sem =>
97 sem ((a->b) -> a -> b)
99 -- * Class 'Anythingable'
100 class Anythingable sem where
101 anything :: sem a -> sem a
104 -- * Class 'Bottomable'
105 class Bottomable sem where
108 -- * Class 'Constantable'
109 class Constantable c sem where
110 constant :: c -> sem c
111 constant = liftDerived Fun.. constant
113 FromDerived (Constantable c) sem =>
116 -- * Class 'Eitherable'
117 class Eitherable sem where
118 left :: sem (l -> Either l r)
119 right :: sem (r -> Either l r)
120 left = liftDerived left
121 right = liftDerived right
123 FromDerived Eitherable sem =>
124 sem (l -> Either l r)
126 FromDerived Eitherable sem =>
127 sem (r -> Either l r)
129 -- * Class 'Equalable'
130 class Equalable sem where
131 equal :: Eq a => sem (a -> a -> Bool)
132 equal = liftDerived equal
134 FromDerived Equalable sem =>
135 Eq a => sem (a -> a -> Bool)
139 Abstractable sem => Equalable sem => Eq a =>
140 sem a -> sem a -> sem Bool
141 (==) x y = equal .@ x .@ y
143 -- * Class 'IfThenElseable'
144 class IfThenElseable sem where
145 ifThenElse :: sem Bool -> sem a -> sem a -> sem a
146 ifThenElse = liftDerived3 ifThenElse
147 default ifThenElse ::
148 FromDerived3 IfThenElseable sem =>
149 sem Bool -> sem a -> sem a -> sem a
151 -- * Class 'Inferable'
152 class Inferable a sem where
154 default infer :: FromDerived (Inferable a) sem => sem a
155 infer = liftDerived infer
157 unit :: Inferable () sem => sem ()
159 bool :: Inferable Bool sem => sem Bool
161 char :: Inferable Char sem => sem Char
163 int :: Inferable Int sem => sem Int
165 natural :: Inferable Natural sem => sem Natural
167 string :: Inferable String sem => sem String
170 -- * Class 'Listable'
171 class Listable sem where
172 cons :: sem (a -> [a] -> [a])
174 cons = liftDerived cons
175 nil = liftDerived nil
177 FromDerived Listable sem =>
178 sem (a -> [a] -> [a])
180 FromDerived Listable sem =>
183 -- * Class 'Maybeable'
184 class Maybeable sem where
185 nothing :: sem (Maybe a)
186 just :: sem (a -> Maybe a)
187 nothing = liftDerived nothing
188 just = liftDerived just
190 FromDerived Maybeable sem =>
193 FromDerived Maybeable sem =>
196 -- * Class 'IsoFunctor'
197 class IsoFunctor sem where
198 (<%>) :: Iso a b -> sem a -> sem b; infixl 4 <%>
199 (<%>) iso = liftDerived1 (iso <%>)
201 FromDerived1 IsoFunctor sem =>
202 Iso a b -> sem a -> sem b
205 data Iso a b = Iso { a2b :: a->b, b2a :: b->a }
206 instance Cat.Category Iso where
207 id = Iso Cat.id Cat.id
208 f . g = Iso (a2b f Cat.. a2b g) (b2a g Cat.. b2a f)
210 -- * Class 'ProductFunctor'
211 -- | Beware that this is an @infixr@,
212 -- not @infixl@ like 'Control.Applicative.<*>';
213 -- this is to follow what is expected by 'ADT'.
214 class ProductFunctor sem where
215 (<.>) :: sem a -> sem b -> sem (a, b); infixr 4 <.>
216 (<.>) = liftDerived2 (<.>)
218 FromDerived2 ProductFunctor sem =>
219 sem a -> sem b -> sem (a, b)
220 (<.) :: sem a -> sem () -> sem a; infixr 4 <.
221 ra <. rb = Iso Tuple.fst (, ()) <%> (ra <.> rb)
222 default (<.) :: IsoFunctor sem => sem a -> sem () -> sem a
223 (.>) :: sem () -> sem a -> sem a; infixr 4 .>
224 ra .> rb = Iso Tuple.snd (() ,) <%> (ra <.> rb)
225 default (.>) :: IsoFunctor sem => sem () -> sem a -> sem a
227 -- * Class 'SumFunctor'
228 -- | Beware that this is an @infixr@,
229 -- not @infixl@ like 'Control.Applicative.<|>';
230 -- this is to follow what is expected by 'ADT'.
231 class SumFunctor sem where
232 (<+>) :: sem a -> sem b -> sem (Either a b); infixr 3 <+>
233 (<+>) = liftDerived2 (<+>)
235 FromDerived2 SumFunctor sem =>
236 sem a -> sem b -> sem (Either a b)
238 -- * Class 'AlternativeFunctor'
239 -- | Beware that this is an @infixr@,
240 -- not @infixl@ like 'Control.Applicative.<|>';
241 -- this is to follow what is expected by 'ADT'.
242 class AlternativeFunctor sem where
243 (<|>) :: sem a -> sem a -> sem a; infixr 3 <|>
244 (<|>) = liftDerived2 (<|>)
246 FromDerived2 AlternativeFunctor sem =>
247 sem a -> sem a -> sem a
249 -- * Class 'Dicurryable'
250 class Dicurryable sem where
254 (args-..->a) -> -- construction
255 (a->Tuples args) -> -- destruction
258 dicurry args constr destr = liftDerived1 (dicurry args constr destr)
260 FromDerived1 Dicurryable sem =>
274 Tuples args ~ EoT (ADT a) =>
275 (args ~ Args (args-..->a)) =>
279 construct f = dicurry (Proxy::Proxy args) f eotOfadt
287 sem (EoT (ADT adt)) ->
289 adt = (<%>) (Iso adtOfeot eotOfadt)
291 -- * Class 'IfSemantic'
292 -- | 'IfSemantic' enables to change the 'Syntax' for a specific 'Semantic'.
294 -- Useful when a 'Semantic' does not implement some 'Syntax'es used by other 'Semantic's.
297 (thenSyntaxes :: [Syntax])
298 (elseSyntaxes :: [Syntax])
303 (Syntaxes thenSyntaxes thenSemantic => thenSemantic a) ->
304 (Syntaxes elseSyntaxes elseSemantic => elseSemantic a) ->
308 Syntaxes thenSyntaxes thenSemantic =>
309 IfSemantic thenSyntaxes elseSyntaxes thenSemantic thenSemantic where
310 ifSemantic thenSyntax _elseSyntax = thenSyntax
312 Syntaxes elseSyntaxes elseSemantic =>
313 IfSemantic thenSyntaxes elseSyntaxes thenSemantic elseSemantic where
314 ifSemantic _thenSyntax elseSyntax = elseSyntax
316 -- * Class 'Monoidable'
326 -- ** Class 'Emptyable'
327 class Emptyable sem where
329 empty = liftDerived empty
331 FromDerived Emptyable sem =>
334 -- ** Class 'Semigroupable'
335 class Semigroupable sem where
336 concat :: Semigroup a => sem (a -> a -> a)
337 concat = liftDerived concat
339 FromDerived Semigroupable sem =>
343 infixr 6 `concat`, <>
345 Abstractable sem => Semigroupable sem => Semigroup a =>
346 sem a -> sem a -> sem a
347 (<>) x y = concat .@ x .@ y
349 -- ** Class 'Optionable'
350 class Optionable sem where
351 optional :: sem a -> sem (Maybe a)
352 optional = liftDerived1 optional
354 FromDerived1 Optionable sem =>
355 sem a -> sem (Maybe a)
357 -- * Class 'Repeatable'
358 class Repeatable sem where
359 many0 :: sem a -> sem [a]
360 many1 :: sem a -> sem [a]
361 many0 = liftDerived1 many0
362 many1 = liftDerived1 many1
364 FromDerived1 Repeatable sem =>
367 FromDerived1 Repeatable sem =>
370 -- | Alias to 'many0'.
371 many :: Repeatable sem => sem a -> sem [a]
374 -- | Alias to 'many1'.
375 some :: Repeatable sem => sem a -> sem [a]
378 -- * Class 'Permutable'
379 class Permutable sem where
380 -- Use @TypeFamilyDependencies@ to help type-inference infer @(sem)@.
381 type Permutation (sem:: Semantic) = (r :: Semantic) | r -> sem
382 type Permutation sem = Permutation (Derived sem)
383 permutable :: Permutation sem a -> sem a
384 perm :: sem a -> Permutation sem a
385 noPerm :: Permutation sem ()
386 permWithDefault :: a -> sem a -> Permutation sem a
388 Eitherable sem => IsoFunctor sem => Permutable sem =>
389 sem a -> Permutation sem (Maybe a)
390 optionalPerm = permWithDefault Nothing Fun.. (<%>) (Iso Just fromJust)
394 ProductFunctor (Permutation sem) =>
397 Permutation sem (a, b)
398 x <&> y = perm x <.> y
406 ProductFunctor (Permutation sem) =>
409 Permutation sem (Maybe a, b)
410 x <?&> y = optionalPerm x <.> y
412 {-# INLINE (<?&>) #-}
419 ProductFunctor (Permutation sem) =>
422 Permutation sem ([a],b)
423 x <*&> y = permWithDefault [] (many1 x) <.> y
425 {-# INLINE (<*&>) #-}
432 ProductFunctor (Permutation sem) =>
435 Permutation sem ([a], b)
436 x <+&> y = perm (many1 x) <.> y
438 {-# INLINE (<+&>) #-}
440 -- * Class 'Routable'
441 class Routable sem where
442 (<!>) :: sem a -> sem b -> sem (a, b); infixr 4 <!>
443 (<!>) = liftDerived2 (<!>)
445 FromDerived2 Routable sem =>
446 sem a -> sem b -> sem (a, b)
448 -- | Like @(,)@ but @infixr@.
449 -- Mostly useful for clarity when using 'Routable'.
450 pattern (:!:) :: a -> b -> (a, b)
451 pattern a:!:b <- (a, b)
455 -- * Class 'Voidable'
456 class Voidable sem where
457 -- | Useful to supply @(a)@ to a @(sem)@ consuming @(a)@,
458 -- for example in the format of a printing interpreter.
459 void :: a -> sem a -> sem ()
460 void = liftDerived1 Fun.. void
462 FromDerived1 Voidable sem =>
465 -- * Class 'Substractable'
466 class Substractable sem where
467 (<->) :: sem a -> sem b -> sem a; infixr 3 <->
468 (<->) = liftDerived2 (<->)
470 FromDerived2 Substractable sem =>
471 sem a -> sem b -> sem a