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 =>
65 class Letable sem where
66 let_ :: sem a -> (sem a -> sem b) -> sem b
67 let_ e b = liftDerived (let_ (derive e) (derive Fun.. b Fun.. liftDerived))
69 FromDerived Letable sem =>
75 -- *** Class 'LetRecable'
76 class LetRecable idx sem where
79 ({-self-} (idx -> sem a) -> idx -> sem a) ->
80 ({-self-} (idx -> sem a) -> sem w) ->
83 FromDerived (LetRecable idx) sem =>
86 ({-self-} (idx -> sem a) -> idx -> sem a) ->
87 ({-self-} (idx -> sem a) -> sem w) ->
93 (\self i -> derive (f (liftDerived Fun.. self) i))
94 (\self -> derive (body (liftDerived Fun.. self)))
96 -- ** Class 'Abstractable1'
97 class Abstractable1 sem where
98 -- | Like 'lam' but whose argument must be used only once,
99 -- hence safe to beta-reduce (inline) without duplicating work.
100 lam1 :: (sem a -> sem b) -> sem (a -> b)
101 lam1 f = liftDerived (lam1 (derive Fun.. f Fun.. liftDerived))
103 FromDerived Abstractable1 sem =>
108 -- ** Class 'Varable'
109 class Varable sem where
110 -- | Mark the use of a variable.
111 var :: sem a -> sem a
112 var = liftDerived1 var
113 default var :: FromDerived1 Varable sem => sem a -> sem a
115 -- ** Class 'Instantiable'
116 class Instantiable sem where
118 (.@) :: sem (a -> b) -> sem a -> sem b
121 (.@) = liftDerived2 (.@)
123 FromDerived2 Instantiable sem =>
128 -- ** Class 'Unabstractable'
130 -- | All operations in lambda calculus can be encoded
131 -- via abstraction elimination into the SK calculus
132 -- as binary trees whose leaves are one
133 -- of the two symbols S ('ap') and K ('const').
134 class Unabstractable sem where
136 ap :: sem ((a -> b -> c) -> (a -> b) -> a -> c)
139 const :: sem (a -> b -> a)
145 (.) :: sem ((b -> c) -> (a -> b) -> a -> c)
150 flip :: sem ((a -> b -> c) -> b -> a -> c)
152 ($) :: sem ((a -> b) -> a -> b)
156 const = liftDerived const
158 (.) = liftDerived (.)
159 flip = liftDerived flip
160 ($) = liftDerived ($)
163 FromDerived Unabstractable sem =>
164 sem ((a -> b -> c) -> (a -> b) -> a -> c)
166 FromDerived Unabstractable sem =>
169 FromDerived Unabstractable sem =>
172 FromDerived Unabstractable sem =>
173 sem ((b -> c) -> (a -> b) -> a -> c)
175 FromDerived Unabstractable sem =>
176 sem ((a -> b -> c) -> b -> a -> c)
178 FromDerived Unabstractable sem =>
179 sem ((a -> b) -> a -> b)
181 -- * Class 'Anythingable'
182 class Anythingable sem where
183 anything :: sem a -> sem a
186 -- * Class 'Bottomable'
187 class Bottomable sem where
190 -- * Class 'Constantable'
191 class Constantable c sem where
192 constant :: c -> sem c
193 constant = liftDerived Fun.. constant
195 FromDerived (Constantable c) sem =>
199 bool :: Constantable Bool sem => Bool -> sem Bool
201 char :: Constantable Char sem => Char -> sem Char
203 int :: Constantable Int sem => Int -> sem Int
205 natural :: Constantable Natural sem => Natural -> sem Natural
207 string :: Constantable String sem => String -> sem String
209 unit :: Constantable () sem => sem ()
212 -- * Class 'Eitherable'
213 class Eitherable sem where
214 either :: sem ((l -> a) -> (r -> a) -> Either l r -> a)
215 left :: sem (l -> Either l r)
216 right :: sem (r -> Either l r)
217 either = liftDerived either
218 left = liftDerived left
219 right = liftDerived right
221 FromDerived Eitherable sem =>
222 sem ((l -> a) -> (r -> a) -> Either l r -> a)
224 FromDerived Eitherable sem =>
225 sem (l -> Either l r)
227 FromDerived Eitherable sem =>
228 sem (r -> Either l r)
230 -- * Class 'Equalable'
231 class Equalable sem where
232 equal :: Eq a => sem (a -> a -> Bool)
233 equal = liftDerived equal
235 FromDerived Equalable sem =>
247 (==) x y = equal .@ x .@ y
249 -- * Class 'IfThenElseable'
250 class IfThenElseable sem where
251 ifThenElse :: sem Bool -> sem a -> sem a -> sem a
252 ifThenElse = liftDerived3 ifThenElse
253 default ifThenElse ::
254 FromDerived3 IfThenElseable sem =>
260 -- * Class 'Inferable'
261 class Inferable a sem where
263 default infer :: FromDerived (Inferable a) sem => sem a
264 infer = liftDerived infer
266 -- * Class 'Listable'
267 class Listable sem where
268 cons :: sem (a -> [a] -> [a])
270 cons = liftDerived cons
271 nil = liftDerived nil
273 FromDerived Listable sem =>
274 sem (a -> [a] -> [a])
276 FromDerived Listable sem =>
279 -- * Class 'Maybeable'
280 class Maybeable sem where
281 nothing :: sem (Maybe a)
282 just :: sem (a -> Maybe a)
283 nothing = liftDerived nothing
284 just = liftDerived just
286 FromDerived Maybeable sem =>
289 FromDerived Maybeable sem =>
292 -- * Class 'IsoFunctor'
293 class IsoFunctor sem where
294 (<%>) :: Iso a b -> sem a -> sem b
296 (<%>) iso = liftDerived1 (iso <%>)
298 FromDerived1 IsoFunctor sem =>
304 data Iso a b = Iso {a2b :: a -> b, b2a :: b -> a}
305 instance Cat.Category Iso where
306 id = Iso Cat.id Cat.id
307 f . g = Iso (a2b f Cat.. a2b g) (b2a g Cat.. b2a f)
309 -- * Class 'ProductFunctor'
311 -- | Beware that this is an @infixr@,
312 -- not @infixl@ like 'Control.Applicative.<*>';
313 -- this is to follow what is expected by 'ADT'.
314 class ProductFunctor sem where
315 (<.>) :: sem a -> sem b -> sem (a, b)
317 (<.>) = liftDerived2 (<.>)
319 FromDerived2 ProductFunctor sem =>
323 (<.) :: sem a -> sem () -> sem a
325 ra <. rb = Iso Tuple.fst (,()) <%> (ra <.> rb)
326 default (<.) :: IsoFunctor sem => sem a -> sem () -> sem a
327 (.>) :: sem () -> sem a -> sem a
329 ra .> rb = Iso Tuple.snd ((),) <%> (ra <.> rb)
330 default (.>) :: IsoFunctor sem => sem () -> sem a -> sem a
332 -- * Class 'SumFunctor'
334 -- | Beware that this is an @infixr@,
335 -- not @infixl@ like 'Control.Applicative.<|>';
336 -- this is to follow what is expected by 'ADT'.
337 class SumFunctor sem where
338 (<+>) :: sem a -> sem b -> sem (Either a b)
340 (<+>) = liftDerived2 (<+>)
342 FromDerived2 SumFunctor sem =>
347 -- | Like @(,)@ but @infixr@.
348 -- Mostly useful for clarity when using 'SumFunctor'.
349 pattern (:!:) :: a -> b -> (a, b)
356 {-# COMPLETE (:!:) #-}
358 -- * Class 'AlternativeFunctor'
360 -- | Beware that this is an @infixr@,
361 -- not @infixl@ like 'Control.Applicative.<|>';
362 -- this is to follow what is expected by 'ADT'.
363 class AlternativeFunctor sem where
364 (<|>) :: sem a -> sem a -> sem a
366 (<|>) = liftDerived2 (<|>)
368 FromDerived2 AlternativeFunctor sem =>
373 -- * Class 'Dicurryable'
374 class Dicurryable sem where
378 (args -..-> a) -> -- construction
379 (a -> Tuples args) -> -- destruction
382 dicurry args constr destr = liftDerived1 (dicurry args constr destr)
384 FromDerived1 Dicurryable sem =>
388 (a -> Tuples args) ->
398 Tuples args ~ EoT (ADT a) =>
399 args ~ Args (args -..-> a) =>
403 construct f = dicurry (Proxy :: Proxy args) f eotOfadt
405 -- * Class 'Dataable'
407 -- | Enable the contruction or deconstruction
408 -- of an 'ADT' (algebraic data type).
409 class Dataable a sem where
410 dataType :: sem (EoT (ADT a)) -> sem a
418 dataType = (<%>) (Iso adtOfeot eotOfadt)
420 -- * Class 'IfSemantic'
422 -- | 'IfSemantic' enables to change the 'Syntax' for a specific 'Semantic'.
424 -- Useful when a 'Semantic' does not implement some 'Syntax'es used by other 'Semantic's.
427 (thenSyntaxes :: [Syntax])
428 (elseSyntaxes :: [Syntax])
433 (Syntaxes thenSyntaxes thenSemantic => thenSemantic a) ->
434 (Syntaxes elseSyntaxes elseSemantic => elseSemantic a) ->
439 Syntaxes thenSyntaxes thenSemantic =>
440 IfSemantic thenSyntaxes elseSyntaxes thenSemantic thenSemantic
442 ifSemantic thenSyntax _elseSyntax = thenSyntax
444 Syntaxes elseSyntaxes elseSemantic =>
445 IfSemantic thenSyntaxes elseSyntaxes thenSemantic elseSemantic
447 ifSemantic _thenSyntax elseSyntax = elseSyntax
449 -- * Class 'Monoidable'
461 -- ** Class 'Emptyable'
462 class Emptyable sem where
464 empty = liftDerived empty
466 FromDerived Emptyable sem =>
469 -- ** Class 'Semigroupable'
470 class Semigroupable sem where
471 concat :: Semigroup a => sem (a -> a -> a)
472 concat = liftDerived concat
474 FromDerived Semigroupable sem =>
478 infixr 6 `concat`, <>
486 (<>) x y = concat .@ x .@ y
488 -- ** Class 'Optionable'
489 class Optionable sem where
490 optional :: sem a -> sem (Maybe a)
491 optional = liftDerived1 optional
493 FromDerived1 Optionable sem =>
497 -- * Class 'Repeatable'
498 class Repeatable sem where
499 many0 :: sem a -> sem [a]
500 many1 :: sem a -> sem [a]
501 many0 = liftDerived1 many0
502 many1 = liftDerived1 many1
504 FromDerived1 Repeatable sem =>
508 FromDerived1 Repeatable sem =>
512 -- | Alias to 'many0'.
513 many :: Repeatable sem => sem a -> sem [a]
516 -- | Alias to 'many1'.
517 some :: Repeatable sem => sem a -> sem [a]
520 -- * Class 'Permutable'
521 class Permutable sem where
522 -- Use @TypeFamilyDependencies@ to help type-inference infer @(sem)@.
523 type Permutation (sem :: Semantic) = (r :: Semantic) | r -> sem
524 type Permutation sem = Permutation (Derived sem)
525 permutable :: Permutation sem a -> sem a
526 perm :: sem a -> Permutation sem a
527 noPerm :: Permutation sem ()
528 permWithDefault :: a -> sem a -> Permutation sem a
534 Permutation sem (Maybe a)
535 optionalPerm = permWithDefault Nothing Fun.. (<%>) (Iso Just fromJust)
539 ProductFunctor (Permutation sem) =>
542 Permutation sem (a, b)
543 x <&> y = perm x <.> y
551 ProductFunctor (Permutation sem) =>
554 Permutation sem (Maybe a, b)
555 x <?&> y = optionalPerm x <.> y
557 {-# INLINE (<?&>) #-}
564 ProductFunctor (Permutation sem) =>
567 Permutation sem ([a], b)
568 x <*&> y = permWithDefault [] (many1 x) <.> y
570 {-# INLINE (<*&>) #-}
577 ProductFunctor (Permutation sem) =>
580 Permutation sem ([a], b)
581 x <+&> y = perm (many1 x) <.> y
583 {-# INLINE (<+&>) #-}
585 -- * Class 'Voidable'
586 class Voidable sem where
587 -- | Useful to supply @(a)@ to a @(sem)@ consuming @(a)@,
588 -- for example in the format of a printing interpreter.
589 void :: a -> sem a -> sem ()
590 void = liftDerived1 Fun.. void
592 FromDerived1 Voidable sem =>
597 -- * Class 'Substractable'
598 class Substractable sem where
599 (<->) :: sem a -> sem b -> sem a
601 (<->) = liftDerived2 (<->)
603 FromDerived2 Substractable sem =>