2 {-# LANGUAGE AllowAmbiguousTypes #-}
4 {-# LANGUAGE DataKinds #-}
6 {-# LANGUAGE PatternSynonyms #-}
8 {-# LANGUAGE RankNTypes #-}
10 {-# LANGUAGE TypeFamilyDependencies #-}
12 {-# LANGUAGE UndecidableInstances #-}
14 -- | This module gathers commonly used tagless-final combinators
15 -- (the syntax part of symantics).
17 -- Note: combinators in this module conflict with usual ones from the @Prelude@
18 -- hence they are meant to be imported either explicitely or qualified.
19 module Symantic.Syntaxes.Classes where
21 import Control.Category qualified as Cat
22 import Data.Bool (Bool (..))
23 import Data.Char (Char)
24 import Data.Either (Either (..))
26 import Data.Function qualified as Fun
28 import Data.Kind (Constraint)
29 import Data.Maybe (Maybe (..), fromJust)
30 import Data.Proxy (Proxy (..))
31 import Data.Semigroup (Semigroup)
32 import Data.String (String)
33 import Data.Tuple qualified as Tuple
34 import GHC.Generics (Generic)
35 import Numeric.Natural (Natural)
37 import Symantic.Syntaxes.CurryN
38 import Symantic.Syntaxes.Derive
39 import Symantic.Syntaxes.EithersOfTuples
42 type Syntax = Semantic -> Constraint
44 -- ** Type family 'Syntaxes'
46 -- | Merge several 'Syntax'es into a single one.
48 -- Useful in 'IfSemantic' or 'All'.
49 type family Syntaxes (syns :: [Syntax]) (sem :: Semantic) :: Constraint where
50 Syntaxes '[] sem = (() :: Constraint)
51 Syntaxes (syn ': syns) sem = ((syn sem, Syntaxes syns sem) :: Constraint)
53 -- * Class 'Abstractable'
54 class Abstractable sem where
55 -- | Lambda term abstraction, in HOAS (Higher-Order Abstract Syntax) style.
56 lam :: (sem a -> sem b) -> sem (a -> b)
57 lam f = liftDerived (lam (derive Fun.. f Fun.. liftDerived))
59 FromDerived Abstractable sem =>
64 -- ** Class 'Abstractable1'
65 class Abstractable1 sem where
66 -- | Like 'lam' but whose argument must be used only once,
67 -- hence safe to beta-reduce (inline) without duplicating work.
68 lam1 :: (sem a -> sem b) -> sem (a -> b)
69 lam1 f = liftDerived (lam1 (derive Fun.. f Fun.. liftDerived))
71 FromDerived Abstractable1 sem =>
77 class Varable sem where
78 -- | Mark the use of a variable.
80 var = liftDerived1 var
81 default var :: FromDerived1 Varable sem => sem a -> sem a
83 -- ** Class 'Instantiable'
84 class Instantiable sem where
86 (.@) :: sem (a -> b) -> sem a -> sem b
89 (.@) = liftDerived2 (.@)
91 FromDerived2 Instantiable sem =>
96 -- ** Class 'Unabstractable'
97 -- | All operations in lambda calculus can be encoded
98 -- via abstraction elimination into the SK calculus
99 -- as binary trees whose leaves are one
100 -- of the three symbols S ('ap') and K ('const').
101 class Unabstractable sem where
103 ap :: sem ((a -> b -> c) -> (a -> b) -> a -> c)
105 const :: sem (a -> b -> a)
109 (.) :: sem ((b -> c) -> (a -> b) -> a -> c)
112 flip :: sem ((a -> b -> c) -> b -> a -> c)
113 ($) :: sem ((a -> b) -> a -> b)
117 const = liftDerived const
119 (.) = liftDerived (.)
120 flip = liftDerived flip
121 ($) = liftDerived ($)
124 FromDerived Unabstractable sem =>
125 sem ((a -> b -> c) -> (a -> b) -> a -> c)
127 FromDerived Unabstractable sem =>
130 FromDerived Unabstractable sem =>
133 FromDerived Unabstractable sem =>
134 sem ((b -> c) -> (a -> b) -> a -> c)
136 FromDerived Unabstractable sem =>
137 sem ((a -> b -> c) -> b -> a -> c)
139 FromDerived Unabstractable sem =>
140 sem ((a -> b) -> a -> b)
142 -- * Class 'Anythingable'
143 class Anythingable sem where
144 anything :: sem a -> sem a
147 -- * Class 'Bottomable'
148 class Bottomable sem where
151 -- * Class 'Constantable'
152 class Constantable c sem where
153 constant :: c -> sem c
154 constant = liftDerived Fun.. constant
156 FromDerived (Constantable c) sem =>
160 -- * Class 'Eitherable'
161 class Eitherable sem where
162 either :: sem ((l -> a) -> (r -> a) -> Either l r -> a)
163 left :: sem (l -> Either l r)
164 right :: sem (r -> Either l r)
165 either = liftDerived either
166 left = liftDerived left
167 right = liftDerived right
169 FromDerived Eitherable sem =>
170 sem ((l -> a) -> (r -> a) -> Either l r -> a)
172 FromDerived Eitherable sem =>
173 sem (l -> Either l r)
175 FromDerived Eitherable sem =>
176 sem (r -> Either l r)
178 -- * Class 'Equalable'
179 class Equalable sem where
180 equal :: Eq a => sem (a -> a -> Bool)
181 equal = liftDerived equal
183 FromDerived Equalable sem =>
196 (==) x y = equal .@ x .@ y
198 -- * Class 'IfThenElseable'
199 class IfThenElseable sem where
200 ifThenElse :: sem Bool -> sem a -> sem a -> sem a
201 ifThenElse = liftDerived3 ifThenElse
202 default ifThenElse ::
203 FromDerived3 IfThenElseable sem =>
209 -- * Class 'Inferable'
210 class Inferable a sem where
212 default infer :: FromDerived (Inferable a) sem => sem a
213 infer = liftDerived infer
215 unit :: Inferable () sem => sem ()
217 bool :: Inferable Bool sem => sem Bool
219 char :: Inferable Char sem => sem Char
221 int :: Inferable Int sem => sem Int
223 natural :: Inferable Natural sem => sem Natural
225 string :: Inferable String sem => sem String
228 -- * Class 'Listable'
229 class Listable sem where
230 cons :: sem (a -> [a] -> [a])
232 cons = liftDerived cons
233 nil = liftDerived nil
235 FromDerived Listable sem =>
236 sem (a -> [a] -> [a])
238 FromDerived Listable sem =>
241 -- * Class 'Maybeable'
242 class Maybeable sem where
243 nothing :: sem (Maybe a)
244 just :: sem (a -> Maybe a)
245 nothing = liftDerived nothing
246 just = liftDerived just
248 FromDerived Maybeable sem =>
251 FromDerived Maybeable sem =>
254 -- * Class 'IsoFunctor'
255 class IsoFunctor sem where
256 (<%>) :: Iso a b -> sem a -> sem b
258 (<%>) iso = liftDerived1 (iso <%>)
260 FromDerived1 IsoFunctor sem =>
266 data Iso a b = Iso {a2b :: a -> b, b2a :: b -> a}
267 instance Cat.Category Iso where
268 id = Iso Cat.id Cat.id
269 f . g = Iso (a2b f Cat.. a2b g) (b2a g Cat.. b2a f)
271 -- * Class 'ProductFunctor'
273 -- | Beware that this is an @infixr@,
274 -- not @infixl@ like 'Control.Applicative.<*>';
275 -- this is to follow what is expected by 'ADT'.
276 class ProductFunctor sem where
277 (<.>) :: sem a -> sem b -> sem (a, b)
279 (<.>) = liftDerived2 (<.>)
281 FromDerived2 ProductFunctor sem =>
285 (<.) :: sem a -> sem () -> sem a
287 ra <. rb = Iso Tuple.fst (,()) <%> (ra <.> rb)
288 default (<.) :: IsoFunctor sem => sem a -> sem () -> sem a
289 (.>) :: sem () -> sem a -> sem a
291 ra .> rb = Iso Tuple.snd ((),) <%> (ra <.> rb)
292 default (.>) :: IsoFunctor sem => sem () -> sem a -> sem a
294 -- * Class 'SumFunctor'
296 -- | Beware that this is an @infixr@,
297 -- not @infixl@ like 'Control.Applicative.<|>';
298 -- this is to follow what is expected by 'ADT'.
299 class SumFunctor sem where
300 (<+>) :: sem a -> sem b -> sem (Either a b)
302 (<+>) = liftDerived2 (<+>)
304 FromDerived2 SumFunctor sem =>
309 -- | Like @(,)@ but @infixr@.
310 -- Mostly useful for clarity when using 'SumFunctor'.
311 pattern (:!:) :: a -> b -> (a, b)
318 {-# COMPLETE (:!:) #-}
320 -- * Class 'AlternativeFunctor'
322 -- | Beware that this is an @infixr@,
323 -- not @infixl@ like 'Control.Applicative.<|>';
324 -- this is to follow what is expected by 'ADT'.
325 class AlternativeFunctor sem where
326 (<|>) :: sem a -> sem a -> sem a
328 (<|>) = liftDerived2 (<|>)
330 FromDerived2 AlternativeFunctor sem =>
335 -- * Class 'Dicurryable'
336 class Dicurryable sem where
340 (args -..-> a) -> -- construction
341 (a -> Tuples args) -> -- destruction
344 dicurry args constr destr = liftDerived1 (dicurry args constr destr)
346 FromDerived1 Dicurryable sem =>
350 (a -> Tuples args) ->
360 Tuples args ~ EoT (ADT a) =>
361 (args ~ Args (args -..-> a)) =>
365 construct f = dicurry (Proxy :: Proxy args) f eotOfadt
367 -- * Class 'Dataable'
369 -- | Enable the contruction or deconstruction
370 -- of an 'ADT' (algebraic data type).
371 class Dataable a sem where
372 dataType :: sem (EoT (ADT a)) -> sem a
380 dataType = (<%>) (Iso adtOfeot eotOfadt)
382 -- * Class 'IfSemantic'
384 -- | 'IfSemantic' enables to change the 'Syntax' for a specific 'Semantic'.
386 -- Useful when a 'Semantic' does not implement some 'Syntax'es used by other 'Semantic's.
389 (thenSyntaxes :: [Syntax])
390 (elseSyntaxes :: [Syntax])
395 (Syntaxes thenSyntaxes thenSemantic => thenSemantic a) ->
396 (Syntaxes elseSyntaxes elseSemantic => elseSemantic a) ->
401 Syntaxes thenSyntaxes thenSemantic =>
402 IfSemantic thenSyntaxes elseSyntaxes thenSemantic thenSemantic
404 ifSemantic thenSyntax _elseSyntax = thenSyntax
406 Syntaxes elseSyntaxes elseSemantic =>
407 IfSemantic thenSyntaxes elseSyntaxes thenSemantic elseSemantic
409 ifSemantic _thenSyntax elseSyntax = elseSyntax
411 -- * Class 'Monoidable'
423 -- ** Class 'Emptyable'
424 class Emptyable sem where
426 empty = liftDerived empty
428 FromDerived Emptyable sem =>
431 -- ** Class 'Semigroupable'
432 class Semigroupable sem where
433 concat :: Semigroup a => sem (a -> a -> a)
434 concat = liftDerived concat
436 FromDerived Semigroupable sem =>
440 infixr 6 `concat`, <>
449 (<>) x y = concat .@ x .@ y
451 -- ** Class 'Optionable'
452 class Optionable sem where
453 optional :: sem a -> sem (Maybe a)
454 optional = liftDerived1 optional
456 FromDerived1 Optionable sem =>
460 -- * Class 'Repeatable'
461 class Repeatable sem where
462 many0 :: sem a -> sem [a]
463 many1 :: sem a -> sem [a]
464 many0 = liftDerived1 many0
465 many1 = liftDerived1 many1
467 FromDerived1 Repeatable sem =>
471 FromDerived1 Repeatable sem =>
475 -- | Alias to 'many0'.
476 many :: Repeatable sem => sem a -> sem [a]
479 -- | Alias to 'many1'.
480 some :: Repeatable sem => sem a -> sem [a]
483 -- * Class 'Permutable'
484 class Permutable sem where
485 -- Use @TypeFamilyDependencies@ to help type-inference infer @(sem)@.
486 type Permutation (sem :: Semantic) = (r :: Semantic) | r -> sem
487 type Permutation sem = Permutation (Derived sem)
488 permutable :: Permutation sem a -> sem a
489 perm :: sem a -> Permutation sem a
490 noPerm :: Permutation sem ()
491 permWithDefault :: a -> sem a -> Permutation sem a
497 Permutation sem (Maybe a)
498 optionalPerm = permWithDefault Nothing Fun.. (<%>) (Iso Just fromJust)
502 ProductFunctor (Permutation sem) =>
505 Permutation sem (a, b)
506 x <&> y = perm x <.> y
514 ProductFunctor (Permutation sem) =>
517 Permutation sem (Maybe a, b)
518 x <?&> y = optionalPerm x <.> y
520 {-# INLINE (<?&>) #-}
527 ProductFunctor (Permutation sem) =>
530 Permutation sem ([a], b)
531 x <*&> y = permWithDefault [] (many1 x) <.> y
533 {-# INLINE (<*&>) #-}
540 ProductFunctor (Permutation sem) =>
543 Permutation sem ([a], b)
544 x <+&> y = perm (many1 x) <.> y
546 {-# INLINE (<+&>) #-}
548 -- * Class 'Voidable'
549 class Voidable sem where
550 -- | Useful to supply @(a)@ to a @(sem)@ consuming @(a)@,
551 -- for example in the format of a printing interpreter.
552 void :: a -> sem a -> sem ()
553 void = liftDerived1 Fun.. void
555 FromDerived1 Voidable sem =>
560 -- * Class 'Substractable'
561 class Substractable sem where
562 (<->) :: sem a -> sem b -> sem a
564 (<->) = liftDerived2 (<->)
566 FromDerived2 Substractable sem =>