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 'Unlifted' 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(..), Ordering(..))
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.Unlifted repr) =>
68 Exception -> repr a -> repr a -> repr a
70 Sym.Liftable repr => CombAlternable (Sym.Unlifted repr) =>
71 ExceptionLabel -> repr a
73 Sym.Liftable1 repr => CombAlternable (Sym.Unlifted repr) =>
76 throw = Sym.lift . throw
79 failure :: SomeFailure -> repr a
81 Sym.Liftable repr => CombAlternable (Sym.Unlifted 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,-}
112 , Show (Failure comb)
113 , TH.Lift (Failure comb)
114 , NFData (Failure comb)
117 SomeFailure (Failure comb {-repr a-})
118 instance Eq SomeFailure where
119 SomeFailure (x::Failure x) == SomeFailure (y::Failure y) =
120 case typeRep @x `eqTypeRep` typeRep @y of
123 instance Ord SomeFailure where
124 SomeFailure (x::Failure x) `compare` SomeFailure (y::Failure y) =
125 -- WARNING: this ordering is convenient to make a 'Set' of 'SomeFailure's
126 -- but it is based upon a hash which changes with packages' ABI
127 -- and also if the install is "inplace" or not.
128 -- Therefore this 'Ord' is not stable enough to put 'SomeFailure'
130 let xT = typeRep @x in
131 let yT = typeRep @y in
132 case SomeTypeRep xT `compare` SomeTypeRep yT of
133 EQ | Just HRefl <- xT `eqTypeRep` yT -> compare x y
135 instance Show SomeFailure where
136 showsPrec p (SomeFailure x) = showsPrec p x
137 instance TH.Lift SomeFailure where
138 liftTyped (SomeFailure x) = [|| SomeFailure $$(TH.liftTyped x) ||]
139 instance NFData SomeFailure where
140 rnf (SomeFailure x) = rnf x
143 instance Trans (SomeFailure repr) repr where
144 trans (SomeFailure x) = trans x
147 -- | @(unSomeFailure c :: 'Maybe' ('Failure' comb repr a))@
148 -- extract the data-constructor from the given 'SomeFailure'
149 -- iif. it belongs to the @('Failure' comb repr a)@ data-instance.
150 unSomeFailure :: forall comb. Typeable comb => SomeFailure -> Maybe (Failure comb)
151 unSomeFailure (SomeFailure (c::Failure c)) =
152 case typeRep @comb `eqTypeRep` typeRep @c of
156 -- ** Type 'Exception'
158 = ExceptionLabel ExceptionLabel
160 deriving (Eq, Ord, Show, TH.Lift, Generic, NFData)
161 type ExceptionLabel = String
162 -- type Exceptions = Set Exception
164 -- | Like @('<|>')@ but with different returning types for the alternatives,
165 -- and a return value wrapped in an 'Either' accordingly.
166 (<+>) :: CombApplicable repr => CombAlternable repr => repr a -> repr b -> repr (Either a b)
167 p <+> q = Prod.left <$> p <|> Prod.right <$> q
169 (<|>) :: CombAlternable repr => repr a -> repr a -> repr a
170 (<|>) = alt ExceptionFailure
174 optionally :: CombApplicable repr => CombAlternable repr => repr a -> Production b -> repr b
175 optionally p x = p $> x <|> pure x
177 optional :: CombApplicable repr => CombAlternable repr => repr a -> repr ()
178 optional = flip optionally Prod.unit
180 option :: CombApplicable repr => CombAlternable repr => Production a -> repr a -> repr a
181 option x p = p <|> pure x
183 choice :: CombAlternable repr => [repr a] -> repr a
184 choice = List.foldr (<|>) empty
185 -- FIXME: Here hlint suggests to use Data.Foldable.asum,
186 -- but at this point there is no asum for our own (<|>)
188 maybeP :: CombApplicable repr => CombAlternable repr => repr a -> repr (Maybe a)
189 maybeP p = option Prod.nothing (Prod.just <$> p)
191 manyTill :: CombApplicable repr => CombAlternable repr => repr a -> repr b -> repr [a]
192 manyTill p end = let go = end $> Prod.nil <|> p <:> go in go
194 -- * Class 'CombApplicable'
195 -- | This is like the usual 'Functor' and 'Applicative' type classes
196 -- from the @base@ package, but using @('Production' a)@ instead of just @(a)@
197 -- to be able to use and pattern match on some usual terms of type @(a)@ (like 'Prod.id')
198 -- and thus apply some optimizations.
199 -- @(repr)@, for "representation", is the usual tagless-final abstraction
200 -- over the many semantics that this syntax (formed by the methods
201 -- of type class like this one) will be interpreted.
202 class CombApplicable repr where
203 -- | @(a2b '<$>' ra)@ parses like @(ra)@ but maps its returned value with @(a2b)@.
204 (<$>) :: Production (a -> b) -> repr a -> repr b
205 (<$>) f = (pure f <*>)
206 (<$>%) :: (Production a -> Production b) -> repr a -> repr b
207 a2b <$>% ma = Prod.lam a2b <$> ma
209 -- | Like '<$>' but with its arguments 'flip'-ped.
210 (<&>) :: repr a -> Production (a -> b) -> repr b
213 -- | @(a '<$' rb)@ parses like @(rb)@ but discards its returned value by replacing it with @(a)@.
214 (<$) :: Production a -> repr b -> repr a
217 -- | @(ra '$>' b)@ parses like @(ra)@ but discards its returned value by replacing it with @(b)@.
218 ($>) :: repr a -> Production b -> repr b
221 -- | @('pure' a)@ parses the empty string, always succeeding in returning @(a)@.
222 pure :: Production a -> repr a
224 Sym.Liftable repr => CombApplicable (Sym.Unlifted repr) =>
225 Production a -> repr a
226 pure = Sym.lift . pure
228 -- | @(ra2b '<*>' ra)@ parses sequentially @(ra2b)@ and then @(ra)@,
229 -- and returns the application of the function returned by @(ra2b)@
230 -- to the value returned by @(ra)@.
231 (<*>) :: repr (a -> b) -> repr a -> repr b
233 Sym.Liftable2 repr => CombApplicable (Sym.Unlifted repr) =>
234 repr (a -> b) -> repr a -> repr b
235 (<*>) = Sym.lift2 (<*>)
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 Prod.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 = (Prod.id <$ x) <*> y
247 -- | Like '<*>' but with its arguments 'flip'-ped.
248 (<**>) :: repr a -> repr (a -> b) -> repr b
249 (<**>) = liftA2 (Prod.flip Prod..@ (Prod.$))
251 (<**>) :: repr a -> repr (a -> b) -> repr b
252 (<**>) = liftA2 (\a f -> f a)
254 -- | @('liftA2' a2b2c ra rb)@ parses sequentially @(ra)@ and then @(rb)@,
255 -- and returns the application of @(a2b2c)@ to the values returned by those parsers.
256 liftA2 :: Production (a -> b -> c) -> repr a -> repr b -> repr c
257 liftA2 f x = (<*>) (f <$> x)
259 infixl 4 <*>, <*, *>, <**>
260 data instance Failure CombApplicable
265 (<:>) :: CombApplicable repr => repr a -> repr [a] -> repr [a]
266 (<:>) = liftA2 Prod.cons
268 sequence :: CombApplicable repr => [repr a] -> repr [a]
269 sequence = List.foldr (<:>) (pure Prod.nil)
271 traverse :: CombApplicable repr => (a -> repr b) -> [a] -> repr [b]
272 traverse f = sequence . List.map f
273 -- FIXME: Here hlint suggests to use Control.Monad.mapM,
274 -- but at this point there is no mapM for our own sequence
276 repeat :: CombApplicable repr => Int -> repr a -> repr [a]
277 repeat n p = traverse (const p) [1..n]
279 between :: CombApplicable repr => repr o -> repr c -> repr a -> repr a
280 between open close p = open *> p <* close
282 void :: CombApplicable repr => repr a -> repr ()
285 unit :: CombApplicable repr => repr ()
286 unit = pure Prod.unit
288 -- * Class 'CombFoldable'
289 class CombFoldable repr where
290 chainPre :: repr (a -> a) -> repr a -> repr a
291 chainPost :: repr a -> repr (a -> a) -> repr a
294 Sym.Liftable2 repr => CombFoldable (Sym.Unlifted repr) =>
295 repr (a -> a) -> repr a -> repr a
297 Sym.Liftable2 repr => CombFoldable (Sym.Unlifted repr) =>
298 repr a -> repr (a -> a) -> repr a
299 chainPre = Sym.lift2 chainPre
300 chainPost = Sym.lift2 chainPost
303 CombApplicable repr =>
304 CombAlternable repr =>
305 repr (a -> a) -> repr a -> repr a
307 CombApplicable repr =>
308 CombAlternable repr =>
309 repr a -> repr (a -> a) -> repr a
310 chainPre op p = go <*> p where go = (Prod..) <$> op <*> go <|> pure Prod.id
311 chainPost p op = p <**> go where go = (Prod..) <$> op <*> go <|> pure Prod.id
313 chainPre op p = flip (foldr ($)) <$> many op <*> p
314 chainPost p op = foldl' (flip ($)) <$> p <*> many op
316 data instance Failure CombFoldable
319 conditional :: CombSelectable repr => [(Production (a -> Bool), repr b)] -> repr a -> repr b -> repr b
320 conditional cs p def = match p fs qs def
321 where (fs, qs) = List.unzip cs
326 CombApplicable repr => CombFoldable repr =>
327 Production (a -> b -> b) -> Production b -> repr a -> repr b
328 pfoldr f k p = chainPre (f <$> p) (pure k)
331 CombApplicable repr => CombFoldable repr =>
332 Production (a -> b -> b) -> Production b -> repr a -> repr b
333 pfoldr1 f k p = f <$> p <*> pfoldr f k p
336 CombApplicable repr => CombFoldable repr =>
337 Production (b -> a -> b) -> Production b -> repr a -> repr b
338 pfoldl f k p = chainPost (pure k) ((Prod.flip <$> pure f) <*> p)
341 CombApplicable repr => CombFoldable repr =>
342 Production (b -> a -> b) -> Production b -> repr a -> repr b
343 pfoldl1 f k p = chainPost (f <$> pure k <*> p) ((Prod.flip <$> pure f) <*> p)
347 CombApplicable repr => CombFoldable repr =>
348 Production (a -> b) -> repr a -> repr (b -> a -> b) -> repr b
349 chainl1' f p op = chainPost (f <$> p) (Prod.flip <$> op <*> p)
352 CombApplicable repr => CombFoldable repr =>
353 repr a -> repr (a -> a -> a) -> repr a
354 chainl1 = chainl1' Prod.id
357 chainr1' :: ParserOps rep => rep (a -> b) -> repr a -> repr (a -> b -> b) -> repr b
358 chainr1' f p op = newRegister_ Prod.id $ \acc ->
359 let go = bind p $ \x ->
360 modify acc (Prod.flip (Prod..@) <$> (op <*> x)) *> go
364 chainr1 :: repr a -> repr (a -> a -> a) -> repr a
365 chainr1 = chainr1' Prod.id
367 chainr :: repr a -> repr (a -> a -> a) -> Production a -> repr a
368 chainr p op x = option x (chainr1 p op)
372 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
373 repr a -> repr (a -> a -> a) -> Production a -> repr a
374 chainl p op x = option x (chainl1 p op)
376 -- Derived Combinators
378 CombApplicable repr => CombFoldable repr =>
380 many = pfoldr Prod.cons Prod.nil
383 CombApplicable repr => CombFoldable repr =>
384 Int -> repr a -> repr [a]
385 manyN n p = List.foldr (const (p <:>)) (many p) [1..n]
388 CombApplicable repr => CombFoldable repr =>
393 CombApplicable repr => CombFoldable repr =>
395 --skipMany p = let skipManyp = p *> skipManyp <|> unit in skipManyp
396 skipMany = void . pfoldl Prod.const Prod.unit -- the void here will encourage the optimiser to recognise that the register is unused
399 CombApplicable repr => CombFoldable repr =>
400 Int -> repr a -> repr ()
401 skipManyN n p = List.foldr (const (p *>)) (skipMany p) [1..n]
404 CombApplicable repr => CombFoldable repr =>
406 skipSome = skipManyN 1
409 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
410 repr a -> repr b -> repr [a]
411 sepBy p sep = option Prod.nil (sepBy1 p sep)
414 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
415 repr a -> repr b -> repr [a]
416 sepBy1 p sep = p <:> many (sep *> p)
419 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
420 repr a -> repr b -> repr [a]
421 endBy p sep = many (p <* sep)
424 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
425 repr a -> repr b -> repr [a]
426 endBy1 p sep = some (p <* sep)
429 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
430 repr a -> repr b -> repr [a]
431 sepEndBy p sep = option Prod.nil (sepEndBy1 p sep)
434 CombApplicable repr => CombAlternable repr => CombFoldable repr =>
435 repr a -> repr b -> repr [a]
437 let seb1 = p <**> (sep *> (Prod.flip Prod..@ Prod.cons <$> option Prod.nil seb1)
438 <|> pure (Prod.flip Prod..@ Prod.cons Prod..@ Prod.nil))
442 sepEndBy1 :: repr a -> repr b -> repr [a]
443 sepEndBy1 p sep = newRegister_ Prod.id $ \acc ->
444 let go = modify acc ((Prod.flip (Prod..)) Prod..@ Prod.cons <$> p)
445 *> (sep *> (go <|> get acc) <|> get acc)
446 in go <*> pure Prod.nil
449 -- * Class 'CombMatchable'
450 class CombMatchable repr where
452 Eq a => repr a -> [Production (a -> Bool)] -> [repr b] -> repr b -> repr b
453 default conditional ::
454 Sym.Unliftable repr => Sym.Liftable1 repr => CombMatchable (Sym.Unlifted repr) =>
455 Eq a => repr a -> [Production (a -> Bool)] -> [repr b] -> repr b -> repr b
456 conditional a ps bs = Sym.lift1 (conditional (Sym.unlift a) ps (Sym.unlift Functor.<$> bs))
458 match :: Eq a => repr a -> [Production a] -> (Production a -> repr b) -> repr b -> repr b
459 match a as a2b = conditional a ((Prod.equal Prod..@) Functor.<$> as) (a2b Functor.<$> as)
460 -- match a as a2b = conditional a (((Prod.eq Prod..@ Prod.qual) Prod..@) Functor.<$> as) (a2b Functor.<$> as)
461 data instance Failure CombMatchable
463 -- * Class 'CombSatisfiable'
464 class CombSatisfiable tok repr where
465 -- | Like 'satisfyOrFail' but with no custom failure.
466 satisfy :: Production (tok -> Bool) -> repr tok
467 satisfy = satisfyOrFail Set.empty
468 -- | Like 'satisfy' but with a custom set of 'SomeFailure's.
471 Production (tok -> Bool) -> repr tok
472 default satisfyOrFail ::
473 Sym.Liftable repr => CombSatisfiable tok (Sym.Unlifted repr) =>
475 Production (tok -> Bool) -> repr tok
476 satisfyOrFail fs = Sym.lift . satisfyOrFail fs
478 data instance Failure (CombSatisfiable tok)
480 -- FIXME: this 'Failure' is a bit special since multiple ones
481 -- with different 'Horizon's makes no sense.
482 -- This should likely be treated separately in 'ParsingError'.
483 | FailureHorizon Int -- FIXME: use Natural?
484 | FailureLabel String
486 deriving (Eq, Ord, Show, Typeable, Generic, NFData)
487 -- | Global 'TH.Name' to refer to the @(InputToken inp)@ type
488 -- from TemplateHaskell code.
489 inputTokenProxy :: TH.Name
490 inputTokenProxy = TH.mkName "inputToken"
491 instance TH.Lift tok => TH.Lift (Failure (CombSatisfiable tok)) where
492 liftTyped :: forall m. TH.Quote m => Failure (CombSatisfiable tok) -> TH.Code m (Failure (CombSatisfiable tok))
495 $$(let inputToken :: TH.Code m (Proxy tok) =
496 TH.unsafeCodeCoerce (return (TH.VarE inputTokenProxy))
498 (Proxy :: Proxy tok') ->
500 FailureAny -> [|| FailureAny @tok' ||]
501 FailureHorizon h -> [|| FailureHorizon @tok' h ||]
502 FailureLabel lbl -> [|| FailureLabel @tok' lbl ||]
503 FailureToken tok -> [|| FailureToken $$(TH.liftTyped tok) ||]
508 CombApplicable repr =>
509 CombSatisfiable Char repr =>
511 char c = satisfyOrFail
512 (Set.singleton (SomeFailure (FailureToken c)))
513 (Prod.equal Prod..@ Prod.char c)
516 item :: forall tok repr.
517 Ord tok => Show tok => Typeable tok => TH.Lift tok => NFData tok =>
518 CombSatisfiable tok repr => repr tok
520 (Set.singleton (SomeFailure (FailureAny @tok)))
521 (Prod.const Prod..@ Prod.bool True)
524 CombAlternable repr =>
525 CombSatisfiable Char repr =>
530 CombApplicable repr => CombAlternable repr =>
531 CombSatisfiable Char repr =>
532 [Char] -> repr [Char]
533 string = try . traverse char
536 Ord tok => Show tok => Typeable tok => TH.Lift tok => NFData tok =>
537 CombSatisfiable tok repr =>
539 oneOf ts = satisfyOrFail
540 (Set.fromList (SomeFailure . FailureToken Functor.<$> ts))
543 [||\t -> $$(ofChars ts [||t||])||])
546 TH.Lift tok => Eq tok =>
547 CombSatisfiable tok repr =>
549 noneOf cs = satisfy (production
550 (not . (`List.elem` cs))
551 [||\c -> not $$(ofChars cs [||c||])||])
554 TH.Lift tok => Eq tok =>
555 {-alternatives-}[tok] ->
556 {-input-}TH.CodeQ tok ->
558 ofChars = List.foldr (\tok acc ->
559 \inp -> [|| tok == $$inp || $$(acc inp) ||])
563 CombAlternable repr =>
564 CombApplicable repr =>
565 CombSatisfiable Char repr =>
566 CombLookable repr => repr ()
567 more = look (void (item @Char))
570 TH.Lift tok => Show tok => Eq tok => Typeable tok =>
571 CombAlternable repr =>
572 CombApplicable repr =>
573 CombSatisfiable tok repr =>
575 token tok = satisfy (Prod.equal Prod..@ Prod.constant tok) $> Prod.constant tok
576 -- token tok = satisfy [ExceptionToken tok] (Prod.eq Prod..@ Prod.qual Prod..@ Prod.char tok) $> Prod.char tok
579 TH.Lift tok => Eq tok => Show tok => Typeable tok =>
580 CombApplicable repr => CombAlternable repr =>
581 CombSatisfiable tok repr => [tok] -> repr [tok]
582 tokens = try . traverse token
584 -- * Class 'CombSelectable'
585 class CombSelectable repr where
586 branch :: repr (Either a b) -> repr (a -> c) -> repr (b -> c) -> repr c
588 Sym.Liftable3 repr => CombSelectable (Sym.Unlifted repr) =>
589 repr (Either a b) -> repr (a -> c) -> repr (b -> c) -> repr c
590 branch = Sym.lift3 branch
591 data instance Failure CombSelectable
593 -- * Class 'CombLookable'
594 class CombLookable repr where
595 look :: repr a -> repr a
596 negLook :: repr a -> repr ()
597 default look :: Sym.Liftable1 repr => CombLookable (Sym.Unlifted repr) => repr a -> repr a
598 default negLook :: Sym.Liftable1 repr => CombLookable (Sym.Unlifted repr) => repr a -> repr ()
599 look = Sym.lift1 look
600 negLook = Sym.lift1 negLook
604 default eof :: Sym.Liftable repr => CombLookable (Sym.Unlifted repr) => repr ()
605 -- eof = negLook (satisfy @Char (Prod.const Prod..@ Prod.bool True))
607 data instance Failure CombLookable
609 deriving (Eq, Ord, Show, Typeable, TH.Lift, Generic, NFData)
611 -- Composite Combinators
612 -- someTill :: repr a -> repr b -> repr [a]
613 -- someTill p end = negLook end *> (p <:> manyTill p end)
616 constp :: CombApplicable repr => repr a -> repr (b -> a)
617 constp = (Prod.const <$>)
622 (>>) :: CombApplicable repr => repr a -> repr b -> repr b
625 -- Monoidal Operations
628 (<~>) :: CombApplicable repr => repr a -> repr b -> repr (a, b)
629 (<~>) = liftA2 (Prod.runtime (,))
632 (<~) :: CombApplicable repr => repr a -> repr b -> repr a
636 (~>) :: CombApplicable repr => repr a -> repr b -> repr b
641 CombApplicable repr =>
642 Production (a -> b -> c) -> repr a -> repr b -> repr c
643 liftA2 f x = (<*>) (fmap f x)
646 CombApplicable repr =>
647 Production (a -> b -> c -> d) -> repr a -> repr b -> repr c -> repr d
648 liftA3 f a b c = liftA2 f a b <*> c
653 -- Combinators interpreters for 'Sym.Any'.
654 instance CombApplicable repr => CombApplicable (Sym.Any repr)
655 instance CombSatisfiable repr => CombSatisfiable (Sym.Any repr)
656 instance CombAlternable repr => CombAlternable (Sym.Any repr)
657 instance CombSelectable repr => CombSelectable (Sym.Any repr)
658 instance CombMatchable repr => CombMatchable (Sym.Any repr)
659 instance CombLookable repr => CombLookable (Sym.Any repr)
660 instance CombFoldable repr => CombFoldable (Sym.Any repr)