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.Typed.Trans as Sym
46 import qualified Symantic.Typed.Lang as Prod
47 import Symantic.Parser.Grammar.Production
50 type ReprComb = Type -> Type
52 -- * Class 'CombAlternable'
53 class CombAlternable repr where
54 -- | @('alt' es l r)@ parses @(l)@ and return its return value or,
55 -- if it fails with an 'Exception' within @(es)@,
56 -- parses @(r)@ from where @(l)@ has left the input stream,
57 -- and returns its return value,
58 -- otherwise throw the 'Exception' again.
59 alt :: Exception -> repr a -> repr a -> repr a
60 throw :: ExceptionLabel -> repr a
61 -- | @('try' ra)@ records the input stream position,
62 -- then parses like @(ra)@ and either returns its value it it succeeds or fails
63 -- if it fails but with a reset of the input stream to the recorded position.
64 -- Generally used on the first alternative: @('try' rl '<|>' rr)@.
65 try :: repr a -> repr a
67 Sym.Liftable2 repr => CombAlternable (Sym.Output repr) =>
68 Exception -> repr a -> repr a -> repr a
70 Sym.Liftable repr => CombAlternable (Sym.Output repr) =>
71 ExceptionLabel -> repr a
73 Sym.Liftable1 repr => CombAlternable (Sym.Output repr) =>
76 throw = Sym.lift . throw
79 failure :: SomeFailure -> repr a
81 Sym.Liftable repr => CombAlternable (Sym.Output repr) =>
83 failure = Sym.lift . failure
85 -- | @(empty)@ parses nothing, always failing to return a value.
87 empty = failure (SomeFailure FailureEmpty)
89 data instance Failure CombAlternable
91 deriving (Eq, Ord, Show, TH.Lift, Generic, NFData)
93 -- ** Data family 'Failure'
94 -- | 'Failure's of the 'Grammar'.
95 -- This is an extensible data-type.
97 (comb :: ReprComb -> Constraint)
101 -- | Convenient utility to pattern-match a 'SomeFailure'.
102 pattern Failure :: Typeable comb => Failure comb -> SomeFailure
103 pattern Failure x <- (unSomeFailure -> Just x)
106 -- ** Type 'SomeFailure'
109 ({-Trans (Failure comb repr) repr,-}
111 , Show (Failure comb)
112 , TH.Lift (Failure comb)
113 , NFData (Failure comb)
116 SomeFailure (Failure comb {-repr a-})
117 instance Eq SomeFailure where
118 SomeFailure (_x::Failure x) == SomeFailure (_y::Failure y) =
119 case typeRep @x `eqTypeRep` typeRep @y of
122 instance Ord SomeFailure where
123 SomeFailure (_x::Failure x) `compare` SomeFailure (_y::Failure y) =
124 SomeTypeRep (typeRep @x) `compare`
125 SomeTypeRep (typeRep @y)
126 instance Show SomeFailure where
127 showsPrec p (SomeFailure x) = showsPrec p x
128 instance TH.Lift SomeFailure where
129 liftTyped (SomeFailure x) = [|| SomeFailure $$(TH.liftTyped x) ||]
130 instance NFData SomeFailure where
131 rnf (SomeFailure x) = rnf x
134 instance Trans (SomeFailure repr) repr where
135 trans (SomeFailure x) = trans x
138 -- | @(unSomeFailure c :: 'Maybe' ('Failure' comb repr a))@
139 -- extract the data-constructor from the given 'SomeFailure'
140 -- iif. it belongs to the @('Failure' comb repr a)@ data-instance.
141 unSomeFailure :: forall comb. Typeable comb => SomeFailure -> Maybe (Failure comb)
142 unSomeFailure (SomeFailure (c::Failure c)) =
143 case typeRep @comb `eqTypeRep` typeRep @c of
147 -- ** Type 'Exception'
149 = ExceptionLabel ExceptionLabel
151 deriving (Eq, Ord, Show, TH.Lift, Generic, NFData)
152 type ExceptionLabel = String
153 -- type Exceptions = Set Exception
155 -- | Like @('<|>')@ but with different returning types for the alternatives,
156 -- and a return value wrapped in an 'Either' accordingly.
157 (<+>) :: CombApplicable repr => CombAlternable repr => repr a -> repr b -> repr (Either a b)
158 p <+> q = Prod.left <$> p <|> Prod.right <$> q
160 (<|>) :: CombAlternable repr => repr a -> repr a -> repr a
161 (<|>) = alt ExceptionFailure
165 optionally :: CombApplicable repr => CombAlternable repr => repr a -> Production b -> repr b
166 optionally p x = p $> x <|> pure x
168 optional :: CombApplicable repr => CombAlternable repr => repr a -> repr ()
169 optional = flip optionally Prod.unit
171 option :: CombApplicable repr => CombAlternable repr => Production a -> repr a -> repr a
172 option x p = p <|> pure x
174 choice :: CombAlternable repr => [repr a] -> repr a
175 choice = List.foldr (<|>) empty
176 -- FIXME: Here hlint suggests to use Data.Foldable.asum,
177 -- but at this point there is no asum for our own (<|>)
179 maybeP :: CombApplicable repr => CombAlternable repr => repr a -> repr (Maybe a)
180 maybeP p = option Prod.nothing (Prod.just <$> p)
182 manyTill :: CombApplicable repr => CombAlternable repr => repr a -> repr b -> repr [a]
183 manyTill p end = let go = end $> Prod.nil <|> p <:> go in go
185 -- * Class 'CombApplicable'
186 -- | This is like the usual 'Functor' and 'Applicative' type classes
187 -- from the @base@ package, but using @('Production' a)@ instead of just @(a)@
188 -- to be able to use and pattern match on some usual terms of type @(a)@ (like 'Prod.id')
189 -- and thus apply some optimizations.
190 -- @(repr)@, for "representation", is the usual tagless-final abstraction
191 -- over the many semantics that this syntax (formed by the methods
192 -- of type class like this one) will be interpreted.
193 class CombApplicable repr where
194 -- | @(a2b '<$>' ra)@ parses like @(ra)@ but maps its returned value with @(a2b)@.
195 (<$>) :: Production (a -> b) -> repr a -> repr b
196 (<$>) f = (pure f <*>)
197 (<$>%) :: (Production a -> Production b) -> repr a -> repr b
198 a2b <$>% ma = Prod.lam a2b <$> ma
200 -- | Like '<$>' but with its arguments 'flip'-ped.
201 (<&>) :: repr a -> Production (a -> b) -> repr b
204 -- | @(a '<$' rb)@ parses like @(rb)@ but discards its returned value by replacing it with @(a)@.
205 (<$) :: Production a -> repr b -> repr a
208 -- | @(ra '$>' b)@ parses like @(ra)@ but discards its returned value by replacing it with @(b)@.
209 ($>) :: repr a -> Production b -> repr b
212 -- | @('pure' a)@ parses the empty string, always succeeding in returning @(a)@.
213 pure :: Production a -> repr a
215 Sym.Liftable repr => CombApplicable (Sym.Output repr) =>
216 Production a -> repr a
217 pure = Sym.lift . pure
219 -- | @(ra2b '<*>' ra)@ parses sequentially @(ra2b)@ and then @(ra)@,
220 -- and returns the application of the function returned by @(ra2b)@
221 -- to the value returned by @(ra)@.
222 (<*>) :: repr (a -> b) -> repr a -> repr b
224 Sym.Liftable2 repr => CombApplicable (Sym.Output repr) =>
225 repr (a -> b) -> repr a -> repr b
226 (<*>) = Sym.lift2 (<*>)
228 -- | @(ra '<*' rb)@ parses sequentially @(ra)@ and then @(rb)@,
229 -- and returns like @(ra)@, discarding the return value of @(rb)@.
230 (<*) :: repr a -> repr b -> repr a
231 (<*) = liftA2 Prod.const
233 -- | @(ra '*>' rb)@ parses sequentially @(ra)@ and then @(rb)@,
234 -- and returns like @(rb)@, discarding the return value of @(ra)@.
235 (*>) :: repr a -> repr b -> repr b
236 x *> y = (Prod.id <$ x) <*> y
238 -- | Like '<*>' but with its arguments 'flip'-ped.
239 (<**>) :: repr a -> repr (a -> b) -> repr b
240 (<**>) = liftA2 (Prod.flip Prod..@ (Prod.$))
242 (<**>) :: repr a -> repr (a -> b) -> repr b
243 (<**>) = liftA2 (\a f -> f a)
245 -- | @('liftA2' a2b2c ra rb)@ parses sequentially @(ra)@ and then @(rb)@,
246 -- and returns the application of @(a2b2c)@ to the values returned by those parsers.
247 liftA2 :: Production (a -> b -> c) -> repr a -> repr b -> repr c
248 liftA2 f x = (<*>) (f <$> x)
250 infixl 4 <*>, <*, *>, <**>
251 data instance Failure CombApplicable
256 (<:>) :: CombApplicable repr => repr a -> repr [a] -> repr [a]
257 (<:>) = liftA2 Prod.cons
259 sequence :: CombApplicable repr => [repr a] -> repr [a]
260 sequence = List.foldr (<:>) (pure Prod.nil)
262 traverse :: CombApplicable repr => (a -> repr b) -> [a] -> repr [b]
263 traverse f = sequence . List.map f
264 -- FIXME: Here hlint suggests to use Control.Monad.mapM,
265 -- but at this point there is no mapM for our own sequence
267 repeat :: CombApplicable repr => Int -> repr a -> repr [a]
268 repeat n p = traverse (const p) [1..n]
270 between :: CombApplicable repr => repr o -> repr c -> repr a -> repr a
271 between open close p = open *> p <* close
273 void :: CombApplicable repr => repr a -> repr ()
276 unit :: CombApplicable repr => repr ()
277 unit = pure Prod.unit
279 -- * Class 'CombFoldable'
280 class CombFoldable repr where
281 chainPre :: repr (a -> a) -> repr a -> repr a
282 chainPost :: repr a -> repr (a -> a) -> repr a
285 Sym.Liftable2 repr => CombFoldable (Sym.Output repr) =>
286 repr (a -> a) -> repr a -> repr a
288 Sym.Liftable2 repr => CombFoldable (Sym.Output repr) =>
289 repr a -> repr (a -> a) -> repr a
290 chainPre = Sym.lift2 chainPre
291 chainPost = Sym.lift2 chainPost
294 CombApplicable repr =>
295 CombAlternable repr =>
296 repr (a -> a) -> repr a -> repr a
298 CombApplicable repr =>
299 CombAlternable repr =>
300 repr a -> repr (a -> a) -> repr a
301 chainPre op p = go <*> p where go = (Prod..) <$> op <*> go <|> pure Prod.id
302 chainPost p op = p <**> go where go = (Prod..) <$> op <*> go <|> pure Prod.id
304 chainPre op p = flip (foldr ($)) <$> many op <*> p
305 chainPost p op = foldl' (flip ($)) <$> p <*> many op
307 data instance Failure CombFoldable
310 conditional :: CombSelectable repr => [(Production (a -> Bool), repr b)] -> repr a -> repr b -> repr b
311 conditional cs p def = match p fs qs def
312 where (fs, qs) = List.unzip cs
317 CombApplicable repr => CombFoldable repr =>
318 Production (a -> b -> b) -> Production b -> repr a -> repr b
319 pfoldr f k p = chainPre (f <$> p) (pure k)
322 CombApplicable repr => CombFoldable repr =>
323 Production (a -> b -> b) -> Production b -> repr a -> repr b
324 pfoldr1 f k p = f <$> p <*> pfoldr f k p
327 CombApplicable repr => CombFoldable repr =>
328 Production (b -> a -> b) -> Production b -> repr a -> repr b
329 pfoldl f k p = chainPost (pure k) ((Prod.flip <$> pure f) <*> p)
332 CombApplicable repr => CombFoldable repr =>
333 Production (b -> a -> b) -> Production b -> repr a -> repr b
334 pfoldl1 f k p = chainPost (f <$> pure k <*> p) ((Prod.flip <$> pure f) <*> p)
338 CombApplicable repr => CombFoldable repr =>
339 Production (a -> b) -> repr a -> repr (b -> a -> b) -> repr b
340 chainl1' f p op = chainPost (f <$> p) (Prod.flip <$> op <*> p)
343 CombApplicable repr => CombFoldable repr =>
344 repr a -> repr (a -> a -> a) -> repr a
345 chainl1 = chainl1' Prod.id
348 chainr1' :: ParserOps rep => rep (a -> b) -> repr a -> repr (a -> b -> b) -> repr b
349 chainr1' f p op = newRegister_ Prod.id $ \acc ->
350 let go = bind p $ \x ->
351 modify acc (Prod.flip (Prod..@) <$> (op <*> x)) *> go
355 chainr1 :: repr a -> repr (a -> a -> a) -> repr a
356 chainr1 = chainr1' Prod.id
358 chainr :: repr a -> repr (a -> a -> a) -> Production a -> repr a
359 chainr p op x = option x (chainr1 p op)
363 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
364 repr a -> repr (a -> a -> a) -> Production a -> repr a
365 chainl p op x = option x (chainl1 p op)
367 -- Derived Combinators
369 CombApplicable repr => CombFoldable repr =>
371 many = pfoldr Prod.cons Prod.nil
374 CombApplicable repr => CombFoldable repr =>
375 Int -> repr a -> repr [a]
376 manyN n p = List.foldr (const (p <:>)) (many p) [1..n]
379 CombApplicable repr => CombFoldable repr =>
384 CombApplicable repr => CombFoldable repr =>
386 --skipMany p = let skipManyp = p *> skipManyp <|> unit in skipManyp
387 skipMany = void . pfoldl Prod.const Prod.unit -- the void here will encourage the optimiser to recognise that the register is unused
390 CombApplicable repr => CombFoldable repr =>
391 Int -> repr a -> repr ()
392 skipManyN n p = List.foldr (const (p *>)) (skipMany p) [1..n]
395 CombApplicable repr => CombFoldable repr =>
397 skipSome = skipManyN 1
400 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
401 repr a -> repr b -> repr [a]
402 sepBy p sep = option Prod.nil (sepBy1 p sep)
405 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
406 repr a -> repr b -> repr [a]
407 sepBy1 p sep = p <:> many (sep *> p)
410 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
411 repr a -> repr b -> repr [a]
412 endBy p sep = many (p <* sep)
415 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
416 repr a -> repr b -> repr [a]
417 endBy1 p sep = some (p <* sep)
420 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
421 repr a -> repr b -> repr [a]
422 sepEndBy p sep = option Prod.nil (sepEndBy1 p sep)
425 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
426 repr a -> repr b -> repr [a]
428 let seb1 = p <**> (sep *> (Prod.flip Prod..@ Prod.cons <$> option Prod.nil seb1)
429 <|> pure (Prod.flip Prod..@ Prod.cons Prod..@ Prod.nil))
433 sepEndBy1 :: repr a -> repr b -> repr [a]
434 sepEndBy1 p sep = newRegister_ Prod.id $ \acc ->
435 let go = modify acc ((Prod.flip (Prod..)) Prod..@ Prod.cons <$> p)
436 *> (sep *> (go <|> get acc) <|> get acc)
437 in go <*> pure Prod.nil
440 -- * Class 'CombMatchable'
441 class CombMatchable repr where
443 Eq a => repr a -> [Production (a -> Bool)] -> [repr b] -> repr b -> repr b
444 default conditional ::
445 Sym.Unliftable repr => Sym.Liftable1 repr => CombMatchable (Sym.Output repr) =>
446 Eq a => repr a -> [Production (a -> Bool)] -> [repr b] -> repr b -> repr b
447 conditional a ps bs = Sym.lift1 (conditional (Sym.unlift a) ps (Sym.unlift Functor.<$> bs))
449 match :: Eq a => repr a -> [Production a] -> (Production a -> repr b) -> repr b -> repr b
450 match a as a2b = conditional a ((Prod.equal Prod..@) Functor.<$> as) (a2b Functor.<$> as)
451 -- match a as a2b = conditional a (((Prod.eq Prod..@ Prod.qual) Prod..@) Functor.<$> as) (a2b Functor.<$> as)
452 data instance Failure CombMatchable
454 -- * Class 'CombSatisfiable'
455 class CombSatisfiable tok repr where
456 -- | Like 'satisfyOrFail' but with no custom failure.
457 satisfy :: Production (tok -> Bool) -> repr tok
458 satisfy = satisfyOrFail Set.empty
459 -- | Like 'satisfy' but with a custom set of 'SomeFailure's.
462 Production (tok -> Bool) -> repr tok
463 default satisfyOrFail ::
464 Sym.Liftable repr => CombSatisfiable tok (Sym.Output repr) =>
466 Production (tok -> Bool) -> repr tok
467 satisfyOrFail fs = Sym.lift . satisfyOrFail fs
469 data instance Failure (CombSatisfiable tok)
471 | FailureHorizon Int -- FIXME: use Natural?
472 | FailureLabel String
474 deriving (Eq, Show, Typeable, Generic, NFData)
475 -- | Global 'TH.Name' to refer to the @(InputToken inp)@ type
476 -- from TemplateHaskell code.
477 inputTokenProxy :: TH.Name
478 inputTokenProxy = TH.mkName "inputToken"
479 instance TH.Lift tok => TH.Lift (Failure (CombSatisfiable tok)) where
480 liftTyped :: forall m. TH.Quote m => Failure (CombSatisfiable tok) -> TH.Code m (Failure (CombSatisfiable tok))
483 $$(let inputToken :: TH.Code m (Proxy tok) =
484 TH.unsafeCodeCoerce (return (TH.VarE inputTokenProxy))
486 (Proxy :: Proxy tok') ->
488 FailureAny -> [|| FailureAny @tok' ||]
489 FailureHorizon h -> [|| FailureHorizon @tok' h ||]
490 FailureLabel lbl -> [|| FailureLabel @tok' lbl ||]
491 FailureToken tok -> [|| FailureToken $$(TH.liftTyped tok) ||]
496 CombApplicable repr =>
497 CombSatisfiable Char repr =>
499 char c = satisfyOrFail
500 (Set.singleton (SomeFailure (FailureToken c)))
501 ((Prod.equal Prod..@ Prod.char c))
504 item :: forall tok repr.
505 Eq tok => Show tok => Typeable tok => TH.Lift tok => NFData tok =>
506 CombSatisfiable tok repr => repr tok
508 (Set.singleton (SomeFailure (FailureAny @tok)))
509 (Prod.const Prod..@ Prod.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))
531 [||\t -> $$(ofChars ts [||t||])||])
534 TH.Lift tok => Eq tok =>
535 CombSatisfiable tok repr =>
537 noneOf cs = satisfy (production
538 (not . (`List.elem` cs))
539 [||\c -> not $$(ofChars cs [||c||])||])
542 TH.Lift tok => Eq tok =>
543 {-alternatives-}[tok] ->
544 {-input-}TH.CodeQ tok ->
546 ofChars = List.foldr (\tok acc ->
547 \inp -> [|| tok == $$inp || $$(acc inp) ||])
551 CombAlternable repr =>
552 CombApplicable repr =>
553 CombSatisfiable Char repr =>
554 CombLookable repr => repr ()
555 more = look (void (item @Char))
558 TH.Lift tok => Show tok => Eq tok => Typeable tok =>
559 CombAlternable repr =>
560 CombApplicable repr =>
561 CombSatisfiable tok repr =>
563 token tok = satisfy (Prod.equal Prod..@ Prod.constant tok) $> Prod.constant tok
564 -- token tok = satisfy [ExceptionToken tok] (Prod.eq Prod..@ Prod.qual Prod..@ Prod.char tok) $> Prod.char tok
567 TH.Lift tok => Eq tok => Show tok => Typeable tok =>
568 CombApplicable repr => CombAlternable repr =>
569 CombSatisfiable tok repr => [tok] -> repr [tok]
570 tokens = try . traverse token
572 -- * Class 'CombSelectable'
573 class CombSelectable repr where
574 branch :: repr (Either a b) -> repr (a -> c) -> repr (b -> c) -> repr c
576 Sym.Liftable3 repr => CombSelectable (Sym.Output repr) =>
577 repr (Either a b) -> repr (a -> c) -> repr (b -> c) -> repr c
578 branch = Sym.lift3 branch
579 data instance Failure CombSelectable
581 -- * Class 'CombLookable'
582 class CombLookable repr where
583 look :: repr a -> repr a
584 negLook :: repr a -> repr ()
585 default look :: Sym.Liftable1 repr => CombLookable (Sym.Output repr) => repr a -> repr a
586 default negLook :: Sym.Liftable1 repr => CombLookable (Sym.Output repr) => repr a -> repr ()
587 look = Sym.lift1 look
588 negLook = Sym.lift1 negLook
592 default eof :: Sym.Liftable repr => CombLookable (Sym.Output repr) => repr ()
593 -- eof = negLook (satisfy @Char (Prod.const Prod..@ Prod.bool True))
595 data instance Failure CombLookable
597 deriving (Eq, Show, Typeable, TH.Lift, Generic, NFData)
599 -- Composite Combinators
600 -- someTill :: repr a -> repr b -> repr [a]
601 -- someTill p end = negLook end *> (p <:> manyTill p end)
604 constp :: CombApplicable repr => repr a -> repr (b -> a)
605 constp = (Prod.const <$>)
610 (>>) :: CombApplicable repr => repr a -> repr b -> repr b
613 -- Monoidal Operations
616 (<~>) :: CombApplicable repr => repr a -> repr b -> repr (a, b)
617 (<~>) = liftA2 (Prod.runtime (,))
620 (<~) :: CombApplicable repr => repr a -> repr b -> repr a
624 (~>) :: CombApplicable repr => repr a -> repr b -> repr b
629 CombApplicable repr =>
630 Production (a -> b -> c) -> repr a -> repr b -> repr c
631 liftA2 f x = (<*>) (fmap f x)
634 CombApplicable repr =>
635 Production (a -> b -> c -> d) -> repr a -> repr b -> repr c -> repr d
636 liftA3 f a b c = liftA2 f a b <*> c
641 -- Combinators interpreters for 'Sym.Any'.
642 instance CombApplicable repr => CombApplicable (Sym.Any repr)
643 instance CombSatisfiable repr => CombSatisfiable (Sym.Any repr)
644 instance CombAlternable repr => CombAlternable (Sym.Any repr)
645 instance CombSelectable repr => CombSelectable (Sym.Any repr)
646 instance CombMatchable repr => CombMatchable (Sym.Any repr)
647 instance CombLookable repr => CombLookable (Sym.Any repr)
648 instance CombFoldable repr => CombFoldable (Sym.Any repr)