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.Functor (Functor)
32 import Data.Functor.Identity (Identity(..))
33 import Data.Functor.Product (Product(..))
34 import Data.Function ((.), flip, id, const)
36 import Data.Kind (Type, Constraint)
37 import Data.Maybe (Maybe(..))
39 import Data.String (String)
40 import Text.Show (Show(..))
41 import Type.Reflection (Typeable, typeRep, eqTypeRep, (:~~:)(..), SomeTypeRep(..))
42 import qualified Data.Functor as Functor
43 import qualified Data.List as List
44 import qualified Data.Set as Set
45 import qualified Language.Haskell.TH as TH
46 import qualified Language.Haskell.TH.Syntax as TH
47 import qualified Prelude
49 import qualified Symantic.Univariant.Trans as Sym
50 import qualified Symantic.Univariant.Lang as H
51 import qualified Symantic.Univariant.Data as Prod
52 import qualified Symantic.Univariant.Reify as Reify
53 import qualified Symantic.Univariant.View
54 import Symantic.Parser.Grammar.Production
57 type ReprComb = Type -> Type
59 -- * Class 'CombAlternable'
60 class CombAlternable repr where
61 -- | @('alt' es l r)@ parses @(l)@ and return its return value or,
62 -- if it fails with an 'Exception' within @(es)@,
63 -- parses @(r)@ from where @(l)@ has left the input stream,
64 -- and returns its return value,
65 -- otherwise throw the 'Exception' again.
66 alt :: Exception -> repr a -> repr a -> repr a
67 throw :: ExceptionLabel -> repr a
68 -- | @('try' ra)@ records the input stream position,
69 -- then parses like @(ra)@ and either returns its value it it succeeds or fails
70 -- if it fails but with a reset of the input stream to the recorded position.
71 -- Generally used on the first alternative: @('try' rl '<|>' rr)@.
72 try :: repr a -> repr a
74 Sym.Liftable2 repr => CombAlternable (Sym.Output repr) =>
75 Exception -> repr a -> repr a -> repr a
77 Sym.Liftable repr => CombAlternable (Sym.Output repr) =>
78 ExceptionLabel -> repr a
80 Sym.Liftable1 repr => CombAlternable (Sym.Output repr) =>
83 throw = Sym.lift . throw
86 failure :: SomeFailure -> repr a
88 Sym.Liftable repr => CombAlternable (Sym.Output repr) =>
90 failure = Sym.lift . failure
92 -- | @(empty)@ parses nothing, always failing to return a value.
94 empty = failure (SomeFailure FailureEmpty)
96 data instance Failure CombAlternable
98 deriving (Eq, Ord, Show, TH.Lift, Generic, NFData)
100 -- ** Data family 'Failure'
101 -- | 'Failure's of the 'Grammar'.
102 -- This is an extensible data-type.
104 (comb :: ReprComb -> Constraint)
108 -- | Convenient utility to pattern-match a 'SomeFailure'.
109 pattern Failure :: Typeable comb => Failure comb -> SomeFailure
110 pattern Failure x <- (unSomeFailure -> Just x)
113 -- ** Type 'SomeFailure'
116 ({-Trans (Failure comb repr) repr,-}
118 , Show (Failure comb)
119 , TH.Lift (Failure comb)
120 , NFData (Failure comb)
123 SomeFailure (Failure comb {-repr a-})
124 instance Eq SomeFailure where
125 SomeFailure (_x::Failure x) == SomeFailure (_y::Failure y) =
126 case typeRep @x `eqTypeRep` typeRep @y of
129 instance Ord SomeFailure where
130 SomeFailure (_x::Failure x) `compare` SomeFailure (_y::Failure y) =
131 SomeTypeRep (typeRep @x) `compare`
132 SomeTypeRep (typeRep @y)
133 instance Show SomeFailure where
134 showsPrec p (SomeFailure x) = showsPrec p x
135 instance TH.Lift SomeFailure where
136 liftTyped (SomeFailure x) = [|| SomeFailure $$(TH.liftTyped x) ||]
137 instance NFData SomeFailure where
138 rnf (SomeFailure x) = rnf x
141 instance Trans (SomeFailure repr) repr where
142 trans (SomeFailure x) = trans x
145 -- | @(unSomeFailure c :: 'Maybe' ('Failure' comb repr a))@
146 -- extract the data-constructor from the given 'SomeFailure'
147 -- iif. it belongs to the @('Failure' comb repr a)@ data-instance.
148 unSomeFailure :: forall comb. Typeable comb => SomeFailure -> Maybe (Failure comb)
149 unSomeFailure (SomeFailure (c::Failure c)) =
150 case typeRep @comb `eqTypeRep` typeRep @c of
154 -- ** Type 'Exception'
156 = ExceptionLabel ExceptionLabel
158 deriving (Eq, Ord, Show, TH.Lift, Generic, NFData)
159 type ExceptionLabel = String
160 -- type Exceptions = Set Exception
162 -- | Like @('<|>')@ but with different returning types for the alternatives,
163 -- and a return value wrapped in an 'Either' accordingly.
164 (<+>) :: CombApplicable repr => CombAlternable repr => repr a -> repr b -> repr (Either a b)
165 p <+> q = H.left <$> p <|> H.right <$> q
167 (<|>) :: CombAlternable repr => repr a -> repr a -> repr a
168 (<|>) = alt ExceptionFailure
172 optionally :: CombApplicable repr => CombAlternable repr => repr a -> Production b -> repr b
173 optionally p x = p $> x <|> pure x
175 optional :: CombApplicable repr => CombAlternable repr => repr a -> repr ()
176 optional = flip optionally H.unit
178 option :: CombApplicable repr => CombAlternable repr => Production a -> repr a -> repr a
179 option x p = p <|> pure x
181 choice :: CombAlternable repr => [repr a] -> repr a
182 choice = List.foldr (<|>) empty
183 -- FIXME: Here hlint suggests to use Data.Foldable.asum,
184 -- but at this point there is no asum for our own (<|>)
186 maybeP :: CombApplicable repr => CombAlternable repr => repr a -> repr (Maybe a)
187 maybeP p = option H.nothing (H.just <$> p)
189 manyTill :: CombApplicable repr => CombAlternable repr => repr a -> repr b -> repr [a]
190 manyTill p end = let go = end $> H.nil <|> p <:> go in go
192 -- * Class 'CombApplicable'
193 -- | This is like the usual 'Functor' and 'Applicative' type classes
194 -- from the @base@ package, but using @('Production' a)@ instead of just @(a)@
195 -- to be able to use and pattern match on some usual terms of type @(a)@ (like 'H.id')
196 -- and thus apply some optimizations.
197 -- @(repr)@, for "representation", is the usual tagless-final abstraction
198 -- over the many semantics that this syntax (formed by the methods
199 -- of type class like this one) will be interpreted.
200 class CombApplicable repr where
201 -- | @(a2b '<$>' ra)@ parses like @(ra)@ but maps its returned value with @(a2b)@.
202 (<$>) :: Production (a -> b) -> repr a -> repr b
203 (<$>) f = (pure f <*>)
204 (<$>%) :: (Production a -> Production b) -> repr a -> repr b
205 a2b <$>% ma = H.lam a2b <$> ma
207 -- | Like '<$>' but with its arguments 'flip'-ped.
208 (<&>) :: repr a -> Production (a -> b) -> repr b
211 -- | @(a '<$' rb)@ parses like @(rb)@ but discards its returned value by replacing it with @(a)@.
212 (<$) :: Production a -> repr b -> repr a
215 -- | @(ra '$>' b)@ parses like @(ra)@ but discards its returned value by replacing it with @(b)@.
216 ($>) :: repr a -> Production b -> repr b
219 -- | @('pure' a)@ parses the empty string, always succeeding in returning @(a)@.
220 pure :: Production a -> repr a
222 Sym.Liftable repr => CombApplicable (Sym.Output repr) =>
223 Production a -> repr a
224 pure = Sym.lift . pure
226 -- | @(ra2b '<*>' ra)@ parses sequentially @(ra2b)@ and then @(ra)@,
227 -- and returns the application of the function returned by @(ra2b)@
228 -- to the value returned by @(ra)@.
229 (<*>) :: repr (a -> b) -> repr a -> repr b
231 Sym.Liftable2 repr => CombApplicable (Sym.Output repr) =>
232 repr (a -> b) -> repr a -> repr b
233 (<*>) = Sym.lift2 (<*>)
235 -- | @(ra '<*' rb)@ parses sequentially @(ra)@ and then @(rb)@,
236 -- and returns like @(ra)@, discarding the return value of @(rb)@.
237 (<*) :: repr a -> repr b -> repr a
238 (<*) = liftA2 H.const
240 -- | @(ra '*>' rb)@ parses sequentially @(ra)@ and then @(rb)@,
241 -- and returns like @(rb)@, discarding the return value of @(ra)@.
242 (*>) :: repr a -> repr b -> repr b
243 x *> y = (H.id <$ x) <*> y
245 -- | Like '<*>' but with its arguments 'flip'-ped.
246 (<**>) :: repr a -> repr (a -> b) -> repr b
247 (<**>) = liftA2 (H.flip H..@ (H.$))
249 (<**>) :: repr a -> repr (a -> b) -> repr b
250 (<**>) = liftA2 (\a f -> f a)
252 -- | @('liftA2' a2b2c ra rb)@ parses sequentially @(ra)@ and then @(rb)@,
253 -- and returns the application of @(a2b2c)@ to the values returned by those parsers.
254 liftA2 :: Production (a -> b -> c) -> repr a -> repr b -> repr c
255 liftA2 f x = (<*>) (f <$> x)
257 infixl 4 <*>, <*, *>, <**>
258 data instance Failure CombApplicable
263 (<:>) :: CombApplicable repr => repr a -> repr [a] -> repr [a]
264 (<:>) = liftA2 H.cons
266 sequence :: CombApplicable repr => [repr a] -> repr [a]
267 sequence = List.foldr (<:>) (pure H.nil)
269 traverse :: CombApplicable repr => (a -> repr b) -> [a] -> repr [b]
270 traverse f = sequence . List.map f
271 -- FIXME: Here hlint suggests to use Control.Monad.mapM,
272 -- but at this point there is no mapM for our own sequence
274 repeat :: CombApplicable repr => Int -> repr a -> repr [a]
275 repeat n p = traverse (const p) [1..n]
277 between :: CombApplicable repr => repr o -> repr c -> repr a -> repr a
278 between open close p = open *> p <* close
280 void :: CombApplicable repr => repr a -> repr ()
283 unit :: CombApplicable repr => repr ()
286 -- * Class 'CombFoldable'
287 class CombFoldable repr where
288 chainPre :: repr (a -> a) -> repr a -> repr a
289 chainPost :: repr a -> repr (a -> a) -> repr a
292 Sym.Liftable2 repr => CombFoldable (Sym.Output repr) =>
293 repr (a -> a) -> repr a -> repr a
295 Sym.Liftable2 repr => CombFoldable (Sym.Output repr) =>
296 repr a -> repr (a -> a) -> repr a
297 chainPre = Sym.lift2 chainPre
298 chainPost = Sym.lift2 chainPost
301 CombApplicable repr =>
302 CombAlternable repr =>
303 repr (a -> a) -> repr a -> repr a
305 CombApplicable repr =>
306 CombAlternable repr =>
307 repr a -> repr (a -> a) -> repr a
308 chainPre op p = go <*> p where go = (H..) <$> op <*> go <|> pure H.id
309 chainPost p op = p <**> go where go = (H..) <$> op <*> go <|> pure H.id
311 chainPre op p = flip (foldr ($)) <$> many op <*> p
312 chainPost p op = foldl' (flip ($)) <$> p <*> many op
314 data instance Failure CombFoldable
317 conditional :: CombSelectable repr => [(Production (a -> Bool), repr b)] -> repr a -> repr b -> repr b
318 conditional cs p def = match p fs qs def
319 where (fs, qs) = List.unzip cs
324 CombApplicable repr => CombFoldable repr =>
325 Production (a -> b -> b) -> Production b -> repr a -> repr b
326 pfoldr f k p = chainPre (f <$> p) (pure k)
329 CombApplicable repr => CombFoldable repr =>
330 Production (a -> b -> b) -> Production b -> repr a -> repr b
331 pfoldr1 f k p = f <$> p <*> pfoldr f k p
334 CombApplicable repr => CombFoldable repr =>
335 Production (b -> a -> b) -> Production b -> repr a -> repr b
336 pfoldl f k p = chainPost (pure k) ((H.flip <$> pure f) <*> p)
339 CombApplicable repr => CombFoldable repr =>
340 Production (b -> a -> b) -> Production b -> repr a -> repr b
341 pfoldl1 f k p = chainPost (f <$> pure k <*> p) ((H.flip <$> pure f) <*> p)
345 CombApplicable repr => CombFoldable repr =>
346 Production (a -> b) -> repr a -> repr (b -> a -> b) -> repr b
347 chainl1' f p op = chainPost (f <$> p) (H.flip <$> op <*> p)
350 CombApplicable repr => CombFoldable repr =>
351 repr a -> repr (a -> a -> a) -> repr a
352 chainl1 = chainl1' H.id
355 chainr1' :: ParserOps rep => rep (a -> b) -> repr a -> repr (a -> b -> b) -> repr b
356 chainr1' f p op = newRegister_ H.id $ \acc ->
357 let go = bind p $ \x ->
358 modify acc (H.flip (H..@) <$> (op <*> x)) *> go
362 chainr1 :: repr a -> repr (a -> a -> a) -> repr a
363 chainr1 = chainr1' H.id
365 chainr :: repr a -> repr (a -> a -> a) -> Production a -> repr a
366 chainr p op x = option x (chainr1 p op)
370 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
371 repr a -> repr (a -> a -> a) -> Production a -> repr a
372 chainl p op x = option x (chainl1 p op)
374 -- Derived Combinators
376 CombApplicable repr => CombFoldable repr =>
378 many = pfoldr H.cons H.nil
381 CombApplicable repr => CombFoldable repr =>
382 Int -> repr a -> repr [a]
383 manyN n p = List.foldr (const (p <:>)) (many p) [1..n]
386 CombApplicable repr => CombFoldable repr =>
391 CombApplicable repr => CombFoldable repr =>
393 --skipMany p = let skipManyp = p *> skipManyp <|> unit in skipManyp
394 skipMany = void . pfoldl H.const H.unit -- the void here will encourage the optimiser to recognise that the register is unused
397 CombApplicable repr => CombFoldable repr =>
398 Int -> repr a -> repr ()
399 skipManyN n p = List.foldr (const (p *>)) (skipMany p) [1..n]
402 CombApplicable repr => CombFoldable repr =>
404 skipSome = skipManyN 1
407 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
408 repr a -> repr b -> repr [a]
409 sepBy p sep = option H.nil (sepBy1 p sep)
412 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
413 repr a -> repr b -> repr [a]
414 sepBy1 p sep = p <:> many (sep *> p)
417 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
418 repr a -> repr b -> repr [a]
419 endBy p sep = many (p <* sep)
422 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
423 repr a -> repr b -> repr [a]
424 endBy1 p sep = some (p <* sep)
427 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
428 repr a -> repr b -> repr [a]
429 sepEndBy p sep = option H.nil (sepEndBy1 p sep)
432 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
433 repr a -> repr b -> repr [a]
435 let seb1 = p <**> (sep *> (H.flip H..@ H.cons <$> option H.nil seb1)
436 <|> pure (H.flip H..@ H.cons H..@ H.nil))
440 sepEndBy1 :: repr a -> repr b -> repr [a]
441 sepEndBy1 p sep = newRegister_ H.id $ \acc ->
442 let go = modify acc ((H.flip (H..)) H..@ H.cons <$> p)
443 *> (sep *> (go <|> get acc) <|> get acc)
447 -- * Class 'CombMatchable'
448 class CombMatchable repr where
450 Eq a => repr a -> [Production (a -> Bool)] -> [repr b] -> repr b -> repr b
451 default conditional ::
452 Sym.Unliftable repr => Sym.Liftable1 repr => CombMatchable (Sym.Output repr) =>
453 Eq a => repr a -> [Production (a -> Bool)] -> [repr b] -> repr b -> repr b
454 conditional a ps bs = Sym.lift1 (conditional (Sym.unlift a) ps (Sym.unlift Functor.<$> bs))
456 match :: Eq a => repr a -> [Production a] -> (Production a -> repr b) -> repr b -> repr b
457 match a as a2b = conditional a ((H.equal H..@) Functor.<$> as) (a2b Functor.<$> as)
458 -- match a as a2b = conditional a (((H.eq H..@ H.qual) H..@) Functor.<$> as) (a2b Functor.<$> as)
459 data instance Failure CombMatchable
461 -- * Class 'CombSatisfiable'
462 class CombSatisfiable tok repr where
463 -- | Like 'satisfyOrFail' but with no custom failure.
464 satisfy :: Production (tok -> Bool) -> repr tok
465 satisfy = satisfyOrFail Set.empty
466 -- | Like 'satisfy' but with a custom set of 'SomeFailure's.
469 Production (tok -> Bool) -> repr tok
470 default satisfyOrFail ::
471 Sym.Liftable repr => CombSatisfiable tok (Sym.Output repr) =>
473 Production (tok -> Bool) -> repr tok
474 satisfyOrFail fs = Sym.lift . satisfyOrFail fs
476 data instance Failure (CombSatisfiable tok)
478 | FailureHorizon Int -- FIXME: use Natural?
479 | FailureLabel String
481 deriving (Eq, Show, Typeable, Generic, NFData)
482 -- | Global 'TH.Name' to refer to the @(InputToken inp)@ type
483 -- from TemplateHaskell code.
484 inputTokenProxy :: TH.Name
485 inputTokenProxy = TH.mkName "inputToken"
486 instance TH.Lift tok => TH.Lift (Failure (CombSatisfiable tok)) where
487 liftTyped :: forall m. TH.Quote m => Failure (CombSatisfiable tok) -> TH.Code m (Failure (CombSatisfiable tok))
490 $$(let inputToken :: TH.Code m (Proxy tok) =
491 TH.unsafeCodeCoerce (return (TH.VarE inputTokenProxy))
493 (Proxy :: Proxy tok') ->
495 FailureAny -> [|| FailureAny @tok' ||]
496 FailureHorizon h -> [|| FailureHorizon @tok' h ||]
497 FailureLabel lbl -> [|| FailureLabel @tok' lbl ||]
498 FailureToken tok -> [|| FailureToken $$(TH.liftTyped tok) ||]
503 CombApplicable repr =>
504 CombSatisfiable Char repr =>
506 char c = satisfyOrFail
507 (Set.singleton (SomeFailure (FailureToken c)))
508 ((H.equal H..@ H.char c))
511 item :: forall tok repr.
512 Eq tok => Show tok => Typeable tok => TH.Lift tok => NFData tok =>
513 CombSatisfiable tok repr => repr tok
515 (Set.singleton (SomeFailure (FailureAny @tok)))
516 (H.const H..@ H.bool True)
519 CombAlternable repr =>
520 CombSatisfiable Char repr =>
525 CombApplicable repr => CombAlternable repr =>
526 CombSatisfiable Char repr =>
527 [Char] -> repr [Char]
528 string = try . traverse char
531 Eq tok => Show tok => Typeable tok => TH.Lift tok => NFData tok =>
532 CombSatisfiable tok repr =>
534 oneOf ts = satisfyOrFail
535 (Set.fromList (SomeFailure . FailureToken Functor.<$> ts))
538 [||\t -> $$(ofChars ts [||t||])||])
541 TH.Lift tok => Eq tok =>
542 CombSatisfiable tok repr =>
544 noneOf cs = satisfy (production
545 (not . (`List.elem` cs))
546 [||\c -> not $$(ofChars cs [||c||])||])
549 TH.Lift tok => Eq tok =>
550 {-alternatives-}[tok] ->
551 {-input-}TH.CodeQ tok ->
553 ofChars = List.foldr (\tok acc ->
554 \inp -> [|| tok == $$inp || $$(acc inp) ||])
558 CombAlternable repr =>
559 CombApplicable repr =>
560 CombSatisfiable Char repr =>
561 CombLookable repr => repr ()
562 more = look (void (item @Char))
565 TH.Lift tok => Show tok => Eq tok => Typeable tok =>
566 CombAlternable repr =>
567 CombApplicable repr =>
568 CombSatisfiable tok repr =>
570 token tok = satisfy (H.equal H..@ H.constant tok) $> H.constant tok
571 -- token tok = satisfy [ExceptionToken tok] (H.eq H..@ H.qual H..@ H.char tok) $> H.char tok
574 TH.Lift tok => Eq tok => Show tok => Typeable tok =>
575 CombApplicable repr => CombAlternable repr =>
576 CombSatisfiable tok repr => [tok] -> repr [tok]
577 tokens = try . traverse token
579 -- * Class 'CombSelectable'
580 class CombSelectable repr where
581 branch :: repr (Either a b) -> repr (a -> c) -> repr (b -> c) -> repr c
583 Sym.Liftable3 repr => CombSelectable (Sym.Output repr) =>
584 repr (Either a b) -> repr (a -> c) -> repr (b -> c) -> repr c
585 branch = Sym.lift3 branch
586 data instance Failure CombSelectable
588 -- * Class 'CombLookable'
589 class CombLookable repr where
590 look :: repr a -> repr a
591 negLook :: repr a -> repr ()
592 default look :: Sym.Liftable1 repr => CombLookable (Sym.Output repr) => repr a -> repr a
593 default negLook :: Sym.Liftable1 repr => CombLookable (Sym.Output repr) => repr a -> repr ()
594 look = Sym.lift1 look
595 negLook = Sym.lift1 negLook
599 default eof :: Sym.Liftable repr => CombLookable (Sym.Output repr) => repr ()
600 -- eof = negLook (satisfy @Char (H.const H..@ H.bool True))
602 data instance Failure CombLookable
604 deriving (Eq, Show, Typeable, TH.Lift, Generic, NFData)
606 -- Composite Combinators
607 -- someTill :: repr a -> repr b -> repr [a]
608 -- someTill p end = negLook end *> (p <:> manyTill p end)
611 constp :: CombApplicable repr => repr a -> repr (b -> a)
612 constp = (H.const <$>)
617 (>>) :: CombApplicable repr => repr a -> repr b -> repr b
620 -- Monoidal Operations
623 (<~>) :: CombApplicable repr => repr a -> repr b -> repr (a, b)
624 (<~>) = liftA2 (H.runtime (,))
627 (<~) :: CombApplicable repr => repr a -> repr b -> repr a
631 (~>) :: CombApplicable repr => repr a -> repr b -> repr b
636 CombApplicable repr =>
637 Production (a -> b -> c) -> repr a -> repr b -> repr c
638 liftA2 f x = (<*>) (fmap f x)
641 CombApplicable repr =>
642 Production (a -> b -> c -> d) -> repr a -> repr b -> repr c -> repr d
643 liftA3 f a b c = liftA2 f a b <*> c
648 -- Combinators interpreters for 'Sym.Any'.
649 instance CombApplicable repr => CombApplicable (Sym.Any repr)
650 instance CombSatisfiable repr => CombSatisfiable (Sym.Any repr)
651 instance CombAlternable repr => CombAlternable (Sym.Any repr)
652 instance CombSelectable repr => CombSelectable (Sym.Any repr)
653 instance CombMatchable repr => CombMatchable (Sym.Any repr)
654 instance CombLookable repr => CombLookable (Sym.Any repr)
655 instance CombFoldable repr => CombFoldable (Sym.Any repr)