1 -- The default type signature of type class methods are changed
2 -- to introduce a Liftable constraint and the same type class but on the 'Output' repr,
3 -- this setup avoids to define the method with boilerplate code when its default
4 -- definition with lift* and 'trans' does what is expected by an instance
5 -- of the type class. This is almost as explained in:
6 -- https://ro-che.info/articles/2016-02-03-finally-tagless-boilerplate
7 {-# LANGUAGE DefaultSignatures #-}
8 {-# LANGUAGE DeriveGeneric #-} -- For NFData instances
9 {-# LANGUAGE DeriveAnyClass #-} -- For NFData instances
10 {-# LANGUAGE DeriveLift #-} -- For TH.Lift (Exception tok)
11 {-# LANGUAGE PatternSynonyms #-} -- For Failure
12 {-# LANGUAGE StandaloneDeriving #-} -- For Show (Exception (InputToken inp))
13 {-# LANGUAGE InstanceSigs #-}
14 {-# LANGUAGE TemplateHaskell #-}
15 {-# LANGUAGE ViewPatterns #-} -- For unSomeFailure
16 -- | Semantic of the grammar combinators used to express parsers,
17 -- in the convenient tagless-final encoding.
18 module Symantic.Parser.Grammar.Combinators where
20 import Data.Proxy (Proxy(..))
21 import Control.Monad (Monad(..))
22 import Control.DeepSeq (NFData(..))
23 import GHC.Generics (Generic)
24 -- import Data.Set (Set)
25 -- import GHC.TypeLits (KnownSymbol)
26 import Data.Bool (Bool(..), not, (||))
27 import Data.Char (Char)
28 import Data.Either (Either(..))
29 import Data.Eq (Eq(..))
30 import Data.Ord (Ord(..))
31 import Data.Function ((.), flip, const)
33 import Data.Kind (Type, Constraint)
34 import Data.Maybe (Maybe(..))
36 import Data.String (String)
37 import Text.Show (Show(..))
38 import Type.Reflection (Typeable, typeRep, eqTypeRep, (:~~:)(..), SomeTypeRep(..))
39 import qualified Data.Functor as Functor
40 import qualified Data.List as List
41 import qualified Data.Set as Set
42 import qualified Language.Haskell.TH as TH
43 import qualified Language.Haskell.TH.Syntax as TH
45 import qualified Symantic.Univariant.Trans as Sym
46 import qualified Symantic.Parser.Haskell as H
48 -- * Type 'TermGrammar'
49 type TermGrammar = H.Term H.ValueCode
52 type ReprComb = Type -> Type
54 code :: TH.Lift a => a -> TermGrammar a
55 code x = H.Term (H.ValueCode x [||x||])
57 -- * Class 'CombAlternable'
58 class CombAlternable repr where
59 -- | @('alt' es l r)@ parses @(l)@ and return its return value or,
60 -- if it fails with an 'Exception' within @(es)@,
61 -- parses @(r)@ from where @(l)@ has left the input stream,
62 -- and returns its return value,
63 -- otherwise throw the 'Exception' again.
64 alt :: Exception -> repr a -> repr a -> repr a
65 throw :: ExceptionLabel -> repr a
66 -- | @('try' ra)@ records the input stream position,
67 -- then parses like @(ra)@ and either returns its value it it succeeds or fails
68 -- if it fails but with a reset of the input stream to the recorded position.
69 -- Generally used on the first alternative: @('try' rl '<|>' rr)@.
70 try :: repr a -> repr a
72 Sym.Liftable2 repr => CombAlternable (Sym.Output repr) =>
73 Exception -> repr a -> repr a -> repr a
75 Sym.Liftable repr => CombAlternable (Sym.Output repr) =>
76 ExceptionLabel -> repr a
78 Sym.Liftable1 repr => CombAlternable (Sym.Output repr) =>
81 throw = Sym.lift . throw
84 failure :: SomeFailure -> repr a
86 Sym.Liftable repr => CombAlternable (Sym.Output repr) =>
88 failure = Sym.lift . failure
90 -- | @(empty)@ parses nothing, always failing to return a value.
92 empty = failure (SomeFailure FailureEmpty)
94 data instance Failure CombAlternable
96 deriving (Eq, Ord, Show, TH.Lift, Generic, NFData)
98 -- ** Data family 'Failure'
99 -- | 'Failure's of the 'Grammar'.
100 -- This is an extensible data-type.
102 (comb :: ReprComb -> Constraint)
106 -- | Convenient utility to pattern-match a 'SomeFailure'.
107 pattern Failure :: Typeable comb => Failure comb -> SomeFailure
108 pattern Failure x <- (unSomeFailure -> Just x)
111 -- ** Type 'SomeFailure'
114 ({-Trans (Failure comb repr) repr,-}
116 , Show (Failure comb)
117 , TH.Lift (Failure comb)
118 , NFData (Failure comb)
121 SomeFailure (Failure comb {-repr a-})
122 instance Eq SomeFailure where
123 SomeFailure (_x::Failure x) == SomeFailure (_y::Failure y) =
124 case typeRep @x `eqTypeRep` typeRep @y of
127 instance Ord SomeFailure where
128 SomeFailure (_x::Failure x) `compare` SomeFailure (_y::Failure y) =
129 SomeTypeRep (typeRep @x) `compare`
130 SomeTypeRep (typeRep @y)
131 instance Show SomeFailure where
132 showsPrec p (SomeFailure x) = showsPrec p x
133 instance TH.Lift SomeFailure where
134 liftTyped (SomeFailure x) = [|| SomeFailure $$(TH.liftTyped x) ||]
135 instance NFData SomeFailure where
136 rnf (SomeFailure x) = rnf x
139 instance Trans (SomeFailure repr) repr where
140 trans (SomeFailure x) = trans x
143 -- | @(unSomeFailure c :: 'Maybe' ('Failure' comb repr a))@
144 -- extract the data-constructor from the given 'SomeFailure'
145 -- iif. it belongs to the @('Failure' comb repr a)@ data-instance.
146 unSomeFailure :: forall comb. Typeable comb => SomeFailure -> Maybe (Failure comb)
147 unSomeFailure (SomeFailure (c::Failure c)) =
148 case typeRep @comb `eqTypeRep` typeRep @c of
152 -- ** Type 'Exception'
154 = ExceptionLabel ExceptionLabel
156 deriving (Eq, Ord, Show, TH.Lift, Generic, NFData)
157 type ExceptionLabel = String
158 -- type Exceptions = Set Exception
160 -- | Like @('<|>')@ but with different returning types for the alternatives,
161 -- and a return value wrapped in an 'Either' accordingly.
162 (<+>) :: CombApplicable repr => CombAlternable repr => repr a -> repr b -> repr (Either a b)
163 p <+> q = H.left <$> p <|> H.right <$> q
165 (<|>) :: CombAlternable repr => repr a -> repr a -> repr a
166 (<|>) = alt ExceptionFailure
170 optionally :: CombApplicable repr => CombAlternable repr => repr a -> TermGrammar b -> repr b
171 optionally p x = p $> x <|> pure x
173 optional :: CombApplicable repr => CombAlternable repr => repr a -> repr ()
174 optional = flip optionally H.unit
176 option :: CombApplicable repr => CombAlternable repr => TermGrammar a -> repr a -> repr a
177 option x p = p <|> pure x
179 choice :: CombAlternable repr => [repr a] -> repr a
180 choice = List.foldr (<|>) empty
181 -- FIXME: Here hlint suggests to use Data.Foldable.asum,
182 -- but at this point there is no asum for our own (<|>)
184 maybeP :: CombApplicable repr => CombAlternable repr => repr a -> repr (Maybe a)
185 maybeP p = option H.nothing (H.just <$> p)
187 manyTill :: CombApplicable repr => CombAlternable repr => repr a -> repr b -> repr [a]
188 manyTill p end = let go = end $> H.nil <|> p <:> go in go
191 -- * Class 'CombApplicable'
192 -- | This is like the usual 'Functor' and 'Applicative' type classes
193 -- from the @base@ package, but using @('TermGrammar' a)@ instead of just @(a)@
194 -- to be able to use and pattern match on some usual terms of type @(a)@ (like 'H.id')
195 -- and thus apply some optimizations.
196 -- @(repr)@, for "representation", is the usual tagless-final abstraction
197 -- over the many semantics that this syntax (formed by the methods
198 -- of type class like this one) will be interpreted.
199 class CombApplicable repr where
200 -- | @(a2b '<$>' ra)@ parses like @(ra)@ but maps its returned value with @(a2b)@.
201 (<$>) :: TermGrammar (a -> b) -> repr a -> repr b
202 (<$>) f = (pure f <*>)
204 -- | Like '<$>' but with its arguments 'flip'-ped.
205 (<&>) :: repr a -> TermGrammar (a -> b) -> repr b
208 -- | @(a '<$' rb)@ parses like @(rb)@ but discards its returned value by replacing it with @(a)@.
209 (<$) :: TermGrammar a -> repr b -> repr a
212 -- | @(ra '$>' b)@ parses like @(ra)@ but discards its returned value by replacing it with @(b)@.
213 ($>) :: repr a -> TermGrammar b -> repr b
216 -- | @('pure' a)@ parses the empty string, always succeeding in returning @(a)@.
217 pure :: TermGrammar a -> repr a
219 Sym.Liftable repr => CombApplicable (Sym.Output repr) =>
220 TermGrammar a -> repr a
221 pure = Sym.lift . pure
223 -- | @(ra2b '<*>' ra)@ parses sequentially @(ra2b)@ and then @(ra)@,
224 -- and returns the application of the function returned by @(ra2b)@
225 -- to the value returned by @(ra)@.
226 (<*>) :: repr (a -> b) -> repr a -> repr b
228 Sym.Liftable2 repr => CombApplicable (Sym.Output repr) =>
229 repr (a -> b) -> repr a -> repr b
230 (<*>) = Sym.lift2 (<*>)
232 -- | @('liftA2' a2b2c ra rb)@ parses sequentially @(ra)@ and then @(rb)@,
233 -- and returns the application of @(a2b2c)@ to the values returned by those parsers.
234 liftA2 :: TermGrammar (a -> b -> c) -> repr a -> repr b -> repr c
235 liftA2 f x = (<*>) (f <$> x)
237 -- | @(ra '<*' rb)@ parses sequentially @(ra)@ and then @(rb)@,
238 -- and returns like @(ra)@, discarding the return value of @(rb)@.
239 (<*) :: repr a -> repr b -> repr a
240 (<*) = liftA2 H.const
242 -- | @(ra '*>' rb)@ parses sequentially @(ra)@ and then @(rb)@,
243 -- and returns like @(rb)@, discarding the return value of @(ra)@.
244 (*>) :: repr a -> repr b -> repr b
245 x *> y = (H.id <$ x) <*> y
247 -- | Like '<*>' but with its arguments 'flip'-ped.
248 (<**>) :: repr a -> repr (a -> b) -> repr b
249 (<**>) = liftA2 (H.flip H..@ (H.$))
251 (<**>) :: repr a -> repr (a -> b) -> repr b
252 (<**>) = liftA2 (\a f -> f a)
254 infixl 4 <$>, <&>, <$, $>, <*>, <*, *>, <**>
255 data instance Failure CombApplicable
259 (<:>) :: CombApplicable repr => repr a -> repr [a] -> repr [a]
260 (<:>) = liftA2 H.cons
262 sequence :: CombApplicable repr => [repr a] -> repr [a]
263 sequence = List.foldr (<:>) (pure H.nil)
265 traverse :: CombApplicable repr => (a -> repr b) -> [a] -> repr [b]
266 traverse f = sequence . List.map f
267 -- FIXME: Here hlint suggests to use Control.Monad.mapM,
268 -- but at this point there is no mapM for our own sequence
270 repeat :: CombApplicable repr => Int -> repr a -> repr [a]
271 repeat n p = traverse (const p) [1..n]
273 between :: CombApplicable repr => repr o -> repr c -> repr a -> repr a
274 between open close p = open *> p <* close
276 void :: CombApplicable repr => repr a -> repr ()
279 unit :: CombApplicable repr => repr ()
282 -- * Class 'CombFoldable'
283 class CombFoldable repr where
284 chainPre :: repr (a -> a) -> repr a -> repr a
285 chainPost :: repr a -> repr (a -> a) -> repr a
288 Sym.Liftable2 repr => CombFoldable (Sym.Output repr) =>
289 repr (a -> a) -> repr a -> repr a
291 Sym.Liftable2 repr => CombFoldable (Sym.Output repr) =>
292 repr a -> repr (a -> a) -> repr a
293 chainPre = Sym.lift2 chainPre
294 chainPost = Sym.lift2 chainPost
297 CombApplicable repr =>
298 CombAlternable repr =>
299 repr (a -> a) -> repr a -> repr a
301 CombApplicable repr =>
302 CombAlternable repr =>
303 repr a -> repr (a -> a) -> repr a
304 chainPre op p = go <*> p where go = (H..) <$> op <*> go <|> pure H.id
305 chainPost p op = p <**> go where go = (H..) <$> op <*> go <|> pure H.id
307 chainPre op p = flip (foldr ($)) <$> many op <*> p
308 chainPost p op = foldl' (flip ($)) <$> p <*> many op
310 data instance Failure CombFoldable
313 conditional :: CombSelectable repr => [(TermGrammar (a -> Bool), repr b)] -> repr a -> repr b -> repr b
314 conditional cs p def = match p fs qs def
315 where (fs, qs) = List.unzip cs
320 CombApplicable repr => CombFoldable repr =>
321 TermGrammar (a -> b -> b) -> TermGrammar b -> repr a -> repr b
322 pfoldr f k p = chainPre (f <$> p) (pure k)
325 CombApplicable repr => CombFoldable repr =>
326 TermGrammar (a -> b -> b) -> TermGrammar b -> repr a -> repr b
327 pfoldr1 f k p = f <$> p <*> pfoldr f k p
330 CombApplicable repr => CombFoldable repr =>
331 TermGrammar (b -> a -> b) -> TermGrammar b -> repr a -> repr b
332 pfoldl f k p = chainPost (pure k) ((H.flip <$> pure f) <*> p)
335 CombApplicable repr => CombFoldable repr =>
336 TermGrammar (b -> a -> b) -> TermGrammar b -> repr a -> repr b
337 pfoldl1 f k p = chainPost (f <$> pure k <*> p) ((H.flip <$> pure f) <*> p)
341 CombApplicable repr => CombFoldable repr =>
342 TermGrammar (a -> b) -> repr a -> repr (b -> a -> b) -> repr b
343 chainl1' f p op = chainPost (f <$> p) (H.flip <$> op <*> p)
346 CombApplicable repr => CombFoldable repr =>
347 repr a -> repr (a -> a -> a) -> repr a
348 chainl1 = chainl1' H.id
351 chainr1' :: ParserOps rep => rep (a -> b) -> repr a -> repr (a -> b -> b) -> repr b
352 chainr1' f p op = newRegister_ H.id $ \acc ->
353 let go = bind p $ \x ->
354 modify acc (H.flip (H..@) <$> (op <*> x)) *> go
358 chainr1 :: repr a -> repr (a -> a -> a) -> repr a
359 chainr1 = chainr1' H.id
361 chainr :: repr a -> repr (a -> a -> a) -> TermGrammar a -> repr a
362 chainr p op x = option x (chainr1 p op)
366 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
367 repr a -> repr (a -> a -> a) -> TermGrammar a -> repr a
368 chainl p op x = option x (chainl1 p op)
370 -- Derived Combinators
372 CombApplicable repr => CombFoldable repr =>
374 many = pfoldr H.cons H.nil
377 CombApplicable repr => CombFoldable repr =>
378 Int -> repr a -> repr [a]
379 manyN n p = List.foldr (const (p <:>)) (many p) [1..n]
382 CombApplicable repr => CombFoldable repr =>
387 CombApplicable repr => CombFoldable repr =>
389 --skipMany p = let skipManyp = p *> skipManyp <|> unit in skipManyp
390 skipMany = void . pfoldl H.const H.unit -- the void here will encourage the optimiser to recognise that the register is unused
393 CombApplicable repr => CombFoldable repr =>
394 Int -> repr a -> repr ()
395 skipManyN n p = List.foldr (const (p *>)) (skipMany p) [1..n]
398 CombApplicable repr => CombFoldable repr =>
400 skipSome = skipManyN 1
403 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
404 repr a -> repr b -> repr [a]
405 sepBy p sep = option H.nil (sepBy1 p sep)
408 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
409 repr a -> repr b -> repr [a]
410 sepBy1 p sep = p <:> many (sep *> p)
413 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
414 repr a -> repr b -> repr [a]
415 endBy p sep = many (p <* sep)
418 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
419 repr a -> repr b -> repr [a]
420 endBy1 p sep = some (p <* sep)
423 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
424 repr a -> repr b -> repr [a]
425 sepEndBy p sep = option H.nil (sepEndBy1 p sep)
428 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
429 repr a -> repr b -> repr [a]
431 let seb1 = p <**> (sep *> (H.flip H..@ H.cons <$> option H.nil seb1)
432 <|> pure (H.flip H..@ H.cons H..@ H.nil))
436 sepEndBy1 :: repr a -> repr b -> repr [a]
437 sepEndBy1 p sep = newRegister_ H.id $ \acc ->
438 let go = modify acc ((H.flip (H..)) H..@ H.cons <$> p)
439 *> (sep *> (go <|> get acc) <|> get acc)
443 -- * Class 'CombMatchable'
444 class CombMatchable repr where
446 Eq a => repr a -> [TermGrammar (a -> Bool)] -> [repr b] -> repr b -> repr b
447 default conditional ::
448 Sym.Unliftable repr => Sym.Liftable1 repr => CombMatchable (Sym.Output repr) =>
449 Eq a => repr a -> [TermGrammar (a -> Bool)] -> [repr b] -> repr b -> repr b
450 conditional a ps bs = Sym.lift1 (conditional (Sym.unlift a) ps (Sym.unlift Functor.<$> bs))
452 match :: Eq a => repr a -> [TermGrammar a] -> (TermGrammar a -> repr b) -> repr b -> repr b
453 match a as a2b = conditional a ((H.eq H..@) Functor.<$> as) (a2b Functor.<$> as)
454 -- match a as a2b = conditional a (((H.eq H..@ H.qual) H..@) Functor.<$> as) (a2b Functor.<$> as)
455 data instance Failure CombMatchable
457 -- * Class 'CombSatisfiable'
458 class CombSatisfiable tok repr where
459 -- | Like 'satisfyOrFail' but with no custom failure.
460 satisfy :: TermGrammar (tok -> Bool) -> repr tok
461 satisfy = satisfyOrFail Set.empty
462 -- | Like 'satisfy' but with a custom set of 'SomeFailure's.
465 TermGrammar (tok -> Bool) -> repr tok
466 default satisfyOrFail ::
467 Sym.Liftable repr => CombSatisfiable tok (Sym.Output repr) =>
469 TermGrammar (tok -> Bool) -> repr tok
470 satisfyOrFail fs = Sym.lift . satisfyOrFail fs
472 data instance Failure (CombSatisfiable tok)
474 | FailureHorizon Int -- FIXME: use Natural?
475 | FailureLabel String
477 deriving (Eq, Show, Typeable, Generic, NFData)
478 -- | Global 'TH.Name' to refer to the @(InputToken inp)@ type
479 -- from TemplateHaskell code.
480 inputTokenProxy :: TH.Name
481 inputTokenProxy = TH.mkName "inputToken"
482 instance TH.Lift tok => TH.Lift (Failure (CombSatisfiable tok)) where
483 liftTyped :: forall m. TH.Quote m => Failure (CombSatisfiable tok) -> TH.Code m (Failure (CombSatisfiable tok))
486 $$(let inputToken :: TH.Code m (Proxy tok) =
487 TH.unsafeCodeCoerce (return (TH.VarE inputTokenProxy))
489 (Proxy :: Proxy tok') ->
491 FailureAny -> [|| FailureAny @tok' ||]
492 FailureHorizon h -> [|| FailureHorizon @tok' h ||]
493 FailureLabel lbl -> [|| FailureLabel @tok' lbl ||]
494 FailureToken tok -> [|| FailureToken $$(TH.liftTyped tok) ||]
499 CombApplicable repr =>
500 CombSatisfiable Char repr =>
502 char c = satisfyOrFail (Set.singleton (SomeFailure (FailureToken c)))
503 (H.eq H..@ H.char c) $> H.char c
505 item :: forall tok repr.
506 Eq tok => Show tok => Typeable tok => TH.Lift tok => NFData tok =>
507 CombSatisfiable tok repr => repr tok
508 item = satisfyOrFail (Set.singleton (SomeFailure (FailureAny @tok)))
509 (H.const H..@ H.bool True)
512 CombAlternable repr =>
513 CombSatisfiable Char repr =>
518 CombApplicable repr => CombAlternable repr =>
519 CombSatisfiable Char repr =>
520 [Char] -> repr [Char]
521 string = try . traverse char
524 Eq tok => Show tok => Typeable tok => TH.Lift tok => NFData tok =>
525 CombSatisfiable tok repr =>
527 oneOf ts = satisfyOrFail
528 (Set.fromList (SomeFailure . FailureToken Functor.<$> ts))
529 (Sym.trans H.ValueCode
530 { value = (`List.elem` ts)
531 , code = [||\t -> $$(ofChars ts [||t||])||] })
534 TH.Lift tok => Eq tok =>
535 CombSatisfiable tok repr =>
537 noneOf cs = satisfy (Sym.trans H.ValueCode
538 { value = not . (`List.elem` cs)
539 , code = [||\c -> not $$(ofChars cs [||c||])||]
543 TH.Lift tok => Eq tok =>
544 {-alternatives-}[tok] ->
545 {-input-}TH.CodeQ tok ->
547 ofChars = List.foldr (\tok acc ->
548 \inp -> [|| tok == $$inp || $$(acc inp) ||])
552 CombAlternable repr =>
553 CombApplicable repr =>
554 CombSatisfiable Char repr =>
555 CombLookable repr => repr ()
556 more = look (void (item @Char))
559 TH.Lift tok => Show tok => Eq tok =>
560 CombAlternable repr =>
561 CombApplicable repr =>
562 CombSatisfiable tok repr =>
564 token tok = satisfy (H.eq H..@ H.char tok) $> H.char tok
565 -- token tok = satisfy [ExceptionToken tok] (H.eq H..@ H.qual H..@ H.char tok) $> H.char tok
568 TH.Lift tok => Eq tok => Show tok =>
569 CombApplicable repr => CombAlternable repr =>
570 CombSatisfiable tok repr => [tok] -> repr [tok]
571 tokens = try . traverse token
573 -- * Class 'CombSelectable'
574 class CombSelectable repr where
575 branch :: repr (Either a b) -> repr (a -> c) -> repr (b -> c) -> repr c
577 Sym.Liftable3 repr => CombSelectable (Sym.Output repr) =>
578 repr (Either a b) -> repr (a -> c) -> repr (b -> c) -> repr c
579 branch = Sym.lift3 branch
580 data instance Failure CombSelectable
582 -- * Class 'CombLookable'
583 class CombLookable repr where
584 look :: repr a -> repr a
585 negLook :: repr a -> repr ()
586 default look :: Sym.Liftable1 repr => CombLookable (Sym.Output repr) => repr a -> repr a
587 default negLook :: Sym.Liftable1 repr => CombLookable (Sym.Output repr) => repr a -> repr ()
588 look = Sym.lift1 look
589 negLook = Sym.lift1 negLook
593 default eof :: Sym.Liftable repr => CombLookable (Sym.Output repr) => repr ()
594 -- eof = negLook (satisfy @Char (H.const H..@ H.bool True))
596 data instance Failure CombLookable
598 deriving (Eq, Show, Typeable, TH.Lift, Generic, NFData)
600 -- Composite Combinators
601 -- someTill :: repr a -> repr b -> repr [a]
602 -- someTill p end = negLook end *> (p <:> manyTill p end)
605 constp :: CombApplicable repr => repr a -> repr (b -> a)
606 constp = (H.const <$>)
611 (>>) :: CombApplicable repr => repr a -> repr b -> repr b
614 -- Monoidal Operations
617 (<~>) :: CombApplicable repr => repr a -> repr b -> repr (a, b)
618 (<~>) = liftA2 (H.runtime (,))
621 (<~) :: CombApplicable repr => repr a -> repr b -> repr a
625 (~>) :: CombApplicable repr => repr a -> repr b -> repr b
630 CombApplicable repr =>
631 TermGrammar (a -> b -> c) -> repr a -> repr b -> repr c
632 liftA2 f x = (<*>) (fmap f x)
635 CombApplicable repr =>
636 TermGrammar (a -> b -> c -> d) -> repr a -> repr b -> repr c -> repr d
637 liftA3 f a b c = liftA2 f a b <*> c
642 -- Combinators interpreters for 'Sym.Any'.
643 instance CombApplicable repr => CombApplicable (Sym.Any repr)
644 instance CombSatisfiable repr => CombSatisfiable (Sym.Any repr)
645 instance CombAlternable repr => CombAlternable (Sym.Any repr)
646 instance CombSelectable repr => CombSelectable (Sym.Any repr)
647 instance CombMatchable repr => CombMatchable (Sym.Any repr)
648 instance CombLookable repr => CombLookable (Sym.Any repr)
649 instance CombFoldable repr => CombFoldable (Sym.Any repr)