2 {-# LANGUAGE AllowAmbiguousTypes #-}
4 {-# LANGUAGE DataKinds #-}
6 {-# LANGUAGE PatternSynonyms #-}
8 {-# LANGUAGE RankNTypes #-}
10 {-# LANGUAGE TypeFamilyDependencies #-}
12 {-# LANGUAGE UndecidableInstances #-}
14 -- | Combinators in this module conflict with usual ones from the @Prelude@
15 -- hence they are meant to be imported either explicitely or qualified.
16 module Symantic.Syntaxes.Classes where
18 import Control.Category qualified as Cat
19 import Data.Bool (Bool (..))
20 import Data.Char (Char)
21 import Data.Either (Either (..))
23 import Data.Function qualified as Fun
25 import Data.Kind (Constraint)
26 import Data.Maybe (Maybe (..), fromJust)
27 import Data.Proxy (Proxy (..))
28 import Data.Semigroup (Semigroup)
29 import Data.String (String)
30 import Data.Tuple qualified as Tuple
31 import GHC.Generics (Generic)
32 import Numeric.Natural (Natural)
34 import Symantic.Syntaxes.ADT
35 import Symantic.Syntaxes.CurryN
36 import Symantic.Syntaxes.Derive
39 type Syntax = Semantic -> Constraint
41 -- ** Type family 'Syntaxes'
43 -- | Merge several 'Syntax'es into a single one.
45 -- Useful in 'IfSemantic'.
46 type family Syntaxes (syns :: [Syntax]) (sem :: Semantic) :: Constraint where
48 Syntaxes (syn ': syns) sem = (syn sem, Syntaxes syns sem)
50 -- * Class 'Abstractable'
51 class Unabstractable sem => Abstractable sem where
52 -- | Lambda term abstraction, in HOAS (Higher-Order Abstract Syntax) style.
53 lam :: (sem a -> sem b) -> sem (a -> b)
55 -- | Like 'lam' but whose argument must be used only once,
56 -- hence safe to beta-reduce (inline) without duplicating work.
57 lam1 :: (sem a -> sem b) -> sem (a -> b)
60 lam f = liftDerived (lam (derive Fun.. f Fun.. liftDerived))
61 lam1 f = liftDerived (lam1 (derive Fun.. f Fun.. liftDerived))
62 var = liftDerived1 var
64 FromDerived Abstractable sem =>
69 FromDerived Abstractable sem =>
74 FromDerived1 Abstractable sem =>
78 -- ** Class 'Unabstractable'
79 class Unabstractable sem where
80 -- | Application, aka. unabstract.
81 (.@) :: sem (a -> b) -> sem a -> sem b
84 (.@) = liftDerived2 (.@)
86 FromDerived2 Unabstractable sem =>
91 -- ** Class 'Functionable'
92 class Functionable sem where
93 const :: sem (a -> b -> a)
94 flip :: sem ((a -> b -> c) -> b -> a -> c)
96 (.) :: sem ((b -> c) -> (a -> b) -> a -> c)
98 ($) :: sem ((a -> b) -> a -> b)
100 const = liftDerived const
101 flip = liftDerived flip
103 (.) = liftDerived (.)
104 ($) = liftDerived ($)
106 FromDerived Functionable sem =>
109 FromDerived Functionable sem =>
110 sem ((a -> b -> c) -> b -> a -> c)
112 FromDerived Functionable sem =>
115 FromDerived Functionable sem =>
116 sem ((b -> c) -> (a -> b) -> a -> c)
118 FromDerived Functionable sem =>
119 sem ((a -> b) -> a -> b)
121 -- * Class 'Anythingable'
122 class Anythingable sem where
123 anything :: sem a -> sem a
126 -- * Class 'Bottomable'
127 class Bottomable sem where
130 -- * Class 'Constantable'
131 class Constantable c sem where
132 constant :: c -> sem c
133 constant = liftDerived Fun.. constant
135 FromDerived (Constantable c) sem =>
139 -- * Class 'Eitherable'
140 class Eitherable sem where
141 left :: sem (l -> Either l r)
142 right :: sem (r -> Either l r)
143 left = liftDerived left
144 right = liftDerived right
146 FromDerived Eitherable sem =>
147 sem (l -> Either l r)
149 FromDerived Eitherable sem =>
150 sem (r -> Either l r)
152 -- * Class 'Equalable'
153 class Equalable sem where
154 equal :: Eq a => sem (a -> a -> Bool)
155 equal = liftDerived equal
157 FromDerived Equalable sem =>
169 (==) x y = equal .@ x .@ y
171 -- * Class 'IfThenElseable'
172 class IfThenElseable sem where
173 ifThenElse :: sem Bool -> sem a -> sem a -> sem a
174 ifThenElse = liftDerived3 ifThenElse
175 default ifThenElse ::
176 FromDerived3 IfThenElseable sem =>
182 -- * Class 'Inferable'
183 class Inferable a sem where
185 default infer :: FromDerived (Inferable a) sem => sem a
186 infer = liftDerived infer
188 unit :: Inferable () sem => sem ()
190 bool :: Inferable Bool sem => sem Bool
192 char :: Inferable Char sem => sem Char
194 int :: Inferable Int sem => sem Int
196 natural :: Inferable Natural sem => sem Natural
198 string :: Inferable String sem => sem String
201 -- * Class 'Listable'
202 class Listable sem where
203 cons :: sem (a -> [a] -> [a])
205 cons = liftDerived cons
206 nil = liftDerived nil
208 FromDerived Listable sem =>
209 sem (a -> [a] -> [a])
211 FromDerived Listable sem =>
214 -- * Class 'Maybeable'
215 class Maybeable sem where
216 nothing :: sem (Maybe a)
217 just :: sem (a -> Maybe a)
218 nothing = liftDerived nothing
219 just = liftDerived just
221 FromDerived Maybeable sem =>
224 FromDerived Maybeable sem =>
227 -- * Class 'IsoFunctor'
228 class IsoFunctor sem where
229 (<%>) :: Iso a b -> sem a -> sem b
231 (<%>) iso = liftDerived1 (iso <%>)
233 FromDerived1 IsoFunctor sem =>
239 data Iso a b = Iso {a2b :: a -> b, b2a :: b -> a}
240 instance Cat.Category Iso where
241 id = Iso Cat.id Cat.id
242 f . g = Iso (a2b f Cat.. a2b g) (b2a g Cat.. b2a f)
244 -- * Class 'ProductFunctor'
246 -- | Beware that this is an @infixr@,
247 -- not @infixl@ like 'Control.Applicative.<*>';
248 -- this is to follow what is expected by 'ADT'.
249 class ProductFunctor sem where
250 (<.>) :: sem a -> sem b -> sem (a, b)
252 (<.>) = liftDerived2 (<.>)
254 FromDerived2 ProductFunctor sem =>
258 (<.) :: sem a -> sem () -> sem a
260 ra <. rb = Iso Tuple.fst (,()) <%> (ra <.> rb)
261 default (<.) :: IsoFunctor sem => sem a -> sem () -> sem a
262 (.>) :: sem () -> sem a -> sem a
264 ra .> rb = Iso Tuple.snd ((),) <%> (ra <.> rb)
265 default (.>) :: IsoFunctor sem => sem () -> sem a -> sem a
267 -- * Class 'SumFunctor'
269 -- | Beware that this is an @infixr@,
270 -- not @infixl@ like 'Control.Applicative.<|>';
271 -- this is to follow what is expected by 'ADT'.
272 class SumFunctor sem where
273 (<+>) :: sem a -> sem b -> sem (Either a b)
275 (<+>) = liftDerived2 (<+>)
277 FromDerived2 SumFunctor sem =>
282 -- * Class 'AlternativeFunctor'
284 -- | Beware that this is an @infixr@,
285 -- not @infixl@ like 'Control.Applicative.<|>';
286 -- this is to follow what is expected by 'ADT'.
287 class AlternativeFunctor sem where
288 (<|>) :: sem a -> sem a -> sem a
290 (<|>) = liftDerived2 (<|>)
292 FromDerived2 AlternativeFunctor sem =>
297 -- * Class 'Dicurryable'
298 class Dicurryable sem where
302 (args -..-> a) -> -- construction
303 (a -> Tuples args) -> -- destruction
306 dicurry args constr destr = liftDerived1 (dicurry args constr destr)
308 FromDerived1 Dicurryable sem =>
312 (a -> Tuples args) ->
322 Tuples args ~ EoT (ADT a) =>
323 (args ~ Args (args -..-> a)) =>
327 construct f = dicurry (Proxy :: Proxy args) f eotOfadt
335 sem (EoT (ADT adt)) ->
337 adt = (<%>) (Iso adtOfeot eotOfadt)
339 -- * Class 'IfSemantic'
341 -- | 'IfSemantic' enables to change the 'Syntax' for a specific 'Semantic'.
343 -- Useful when a 'Semantic' does not implement some 'Syntax'es used by other 'Semantic's.
346 (thenSyntaxes :: [Syntax])
347 (elseSyntaxes :: [Syntax])
352 (Syntaxes thenSyntaxes thenSemantic => thenSemantic a) ->
353 (Syntaxes elseSyntaxes elseSemantic => elseSemantic a) ->
358 Syntaxes thenSyntaxes thenSemantic =>
359 IfSemantic thenSyntaxes elseSyntaxes thenSemantic thenSemantic
361 ifSemantic thenSyntax _elseSyntax = thenSyntax
363 Syntaxes elseSyntaxes elseSemantic =>
364 IfSemantic thenSyntaxes elseSyntaxes thenSemantic elseSemantic
366 ifSemantic _thenSyntax elseSyntax = elseSyntax
368 -- * Class 'Monoidable'
380 -- ** Class 'Emptyable'
381 class Emptyable sem where
383 empty = liftDerived empty
385 FromDerived Emptyable sem =>
388 -- ** Class 'Semigroupable'
389 class Semigroupable sem where
390 concat :: Semigroup a => sem (a -> a -> a)
391 concat = liftDerived concat
393 FromDerived Semigroupable sem =>
397 infixr 6 `concat`, <>
405 (<>) x y = concat .@ x .@ y
407 -- ** Class 'Optionable'
408 class Optionable sem where
409 optional :: sem a -> sem (Maybe a)
410 optional = liftDerived1 optional
412 FromDerived1 Optionable sem =>
416 -- * Class 'Repeatable'
417 class Repeatable sem where
418 many0 :: sem a -> sem [a]
419 many1 :: sem a -> sem [a]
420 many0 = liftDerived1 many0
421 many1 = liftDerived1 many1
423 FromDerived1 Repeatable sem =>
427 FromDerived1 Repeatable sem =>
431 -- | Alias to 'many0'.
432 many :: Repeatable sem => sem a -> sem [a]
435 -- | Alias to 'many1'.
436 some :: Repeatable sem => sem a -> sem [a]
439 -- * Class 'Permutable'
440 class Permutable sem where
441 -- Use @TypeFamilyDependencies@ to help type-inference infer @(sem)@.
442 type Permutation (sem :: Semantic) = (r :: Semantic) | r -> sem
443 type Permutation sem = Permutation (Derived sem)
444 permutable :: Permutation sem a -> sem a
445 perm :: sem a -> Permutation sem a
446 noPerm :: Permutation sem ()
447 permWithDefault :: a -> sem a -> Permutation sem a
453 Permutation sem (Maybe a)
454 optionalPerm = permWithDefault Nothing Fun.. (<%>) (Iso Just fromJust)
458 ProductFunctor (Permutation sem) =>
461 Permutation sem (a, b)
462 x <&> y = perm x <.> y
470 ProductFunctor (Permutation sem) =>
473 Permutation sem (Maybe a, b)
474 x <?&> y = optionalPerm x <.> y
476 {-# INLINE (<?&>) #-}
483 ProductFunctor (Permutation sem) =>
486 Permutation sem ([a], b)
487 x <*&> y = permWithDefault [] (many1 x) <.> y
489 {-# INLINE (<*&>) #-}
496 ProductFunctor (Permutation sem) =>
499 Permutation sem ([a], b)
500 x <+&> y = perm (many1 x) <.> y
502 {-# INLINE (<+&>) #-}
504 -- * Class 'Routable'
505 class Routable sem where
506 (<!>) :: sem a -> sem b -> sem (a, b)
508 (<!>) = liftDerived2 (<!>)
510 FromDerived2 Routable sem =>
515 -- | Like @(,)@ but @infixr@.
516 -- Mostly useful for clarity when using 'Routable'.
517 pattern (:!:) :: a -> b -> (a, b)
525 -- * Class 'Voidable'
526 class Voidable sem where
527 -- | Useful to supply @(a)@ to a @(sem)@ consuming @(a)@,
528 -- for example in the format of a printing interpreter.
529 void :: a -> sem a -> sem ()
530 void = liftDerived1 Fun.. void
532 FromDerived1 Voidable sem =>
537 -- * Class 'Substractable'
538 class Substractable sem where
539 (<->) :: sem a -> sem b -> sem a
541 (<->) = liftDerived2 (<->)
543 FromDerived2 Substractable sem =>