{-# LANGUAGE BangPatterns #-}-- |-- Module : Control.Monad.Combinators-- Copyright : © 2017–present Mark Karpov-- License : BSD 3 clause---- Maintainer : Mark Karpov <markkarpov92@gmail.com>-- Stability : experimental-- Portability : portable---- The module provides more efficient versions of the combinators from-- "Control.Applicative.Combinators" defined in terms of 'Monad' and-- 'MonadPlus' instead of 'Control.Applicative.Applicative' and-- 'Control.Applicative.Alternative'. When there is no difference in-- performance we just re-export the combinators from-- "Control.Applicative.Combinators".---- @since 0.4.0moduleControl.Monad.Combinators(-- * Re-exports from "Control.Applicative"(C.<|>),-- $assocboC.optional,-- $optionalC.empty,-- $empty-- * Original combinatorsC.between ,C.choice ,count ,count' ,C.eitherP ,endBy ,endBy1 ,many ,manyTill ,manyTill_ ,some ,someTill ,someTill_ ,C.option ,sepBy ,sepBy1 ,sepEndBy ,sepEndBy1 ,skipMany ,skipSome ,skipCount ,skipManyTill ,skipSomeTill ,)whereimportqualifiedControl.Applicative.Combinators asCimportControl.Monad------------------------------------------------------------------------------ Re-exports from "Control.Applicative"-- $assocbo---- This combinator implements choice. The parser @p 'C.<|>' q@ first applies-- @p@. If it succeeds, the value of @p@ is returned. If @p@ fails, parser-- @q@ is tried.-- $optional---- @'C.optional' p@ tries to apply the parser @p@. It will parse @p@ or-- 'Nothing'. It only fails if @p@ fails after consuming input. On success-- result of @p@ is returned inside of 'Just', on failure 'Nothing' is-- returned.---- See also: 'C.option'.-- $empty---- This parser fails unconditionally without providing any information about-- the cause of the failure.------------------------------------------------------------------------------ Original combinators-- | @'count' n p@ parses @n@ occurrences of @p@. If @n@ is smaller or equal-- to zero, the parser equals to @'return' []@. Returns a list of @n@-- values.---- See also: 'skipCount', 'count''.count ::Monadm =>Int->m a ->m [a ]count :: Int -> m a -> m [a] count Int n' m a p =([a] -> [a]) -> Int -> m [a] forall t c. (Ord t, Num t) => ([a] -> c) -> t -> m c go [a] -> [a] forall a. a -> a idInt n' wherego :: ([a] -> c) -> t -> m c go [a] -> c f !t n =ift n t -> t -> Bool forall a. Ord a => a -> a -> Bool <=t 0thenc -> m c forall (m :: * -> *) a. Monad m => a -> m a return([a] -> c f [])elsedoa x <-m a p ([a] -> c) -> t -> m c go ([a] -> c f ([a] -> c) -> ([a] -> [a]) -> [a] -> c forall b c a. (b -> c) -> (a -> b) -> a -> c .(a x a -> [a] -> [a] forall a. a -> [a] -> [a] :))(t n t -> t -> t forall a. Num a => a -> a -> a -t 1){-# INLINEcount #-}-- | @'count'' m n p@ parses from @m@ to @n@ occurrences of @p@. If @n@ is-- not positive or @m > n@, the parser equals to @'return' []@. Returns a-- list of parsed values.---- Please note that @m@ /may/ be negative, in this case effect is the same-- as if it were equal to zero.---- See also: 'skipCount', 'count'.count' ::MonadPlusm =>Int->Int->m a ->m [a ]count' :: Int -> Int -> m a -> m [a] count' Int m' Int n' m a p =ifInt n' Int -> Int -> Bool forall a. Ord a => a -> a -> Bool >Int 0Bool -> Bool -> Bool &&Int n' Int -> Int -> Bool forall a. Ord a => a -> a -> Bool >=Int m' then([a] -> [a]) -> Int -> m [a] forall t b. (Ord t, Num t) => ([a] -> b) -> t -> m b gom [a] -> [a] forall a. a -> a idInt m' else[a] -> m [a] forall (m :: * -> *) a. Monad m => a -> m a return[]wheregom :: ([a] -> b) -> t -> m b gom [a] -> b f !t m =ift m t -> t -> Bool forall a. Ord a => a -> a -> Bool >t 0thendoa x <-m a p ([a] -> b) -> t -> m b gom ([a] -> b f ([a] -> b) -> ([a] -> [a]) -> [a] -> b forall b c a. (b -> c) -> (a -> b) -> a -> c .(a x a -> [a] -> [a] forall a. a -> [a] -> [a] :))(t m t -> t -> t forall a. Num a => a -> a -> a -t 1)else([a] -> b) -> Int -> m b forall t b. (Ord t, Num t) => ([a] -> b) -> t -> m b god [a] -> b f (ifInt m' Int -> Int -> Bool forall a. Ord a => a -> a -> Bool <=Int 0thenInt n' elseInt n' Int -> Int -> Int forall a. Num a => a -> a -> a -Int m' )god :: ([a] -> a) -> t -> m a god [a] -> a f !t d =ift d t -> t -> Bool forall a. Ord a => a -> a -> Bool >t 0thendoMaybe a r <-m a -> m (Maybe a) forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a) C.optionalm a p caseMaybe a r ofMaybe a Nothing->a -> m a forall (m :: * -> *) a. Monad m => a -> m a return([a] -> a f [])Justa x ->([a] -> a) -> t -> m a god ([a] -> a f ([a] -> a) -> ([a] -> [a]) -> [a] -> a forall b c a. (b -> c) -> (a -> b) -> a -> c .(a x a -> [a] -> [a] forall a. a -> [a] -> [a] :))(t d t -> t -> t forall a. Num a => a -> a -> a -t 1)elsea -> m a forall (m :: * -> *) a. Monad m => a -> m a return([a] -> a f []){-# INLINEcount' #-}-- | @'endBy' p sep@ parses /zero/ or more occurrences of @p@, separated and-- ended by @sep@. Returns a list of values returned by @p@.---- > cStatements = cStatement `endBy` semicolonendBy ::MonadPlusm =>m a ->m sep ->m [a ]endBy :: m a -> m sep -> m [a] endBy m a p m sep sep =m a -> m [a] forall (m :: * -> *) a. MonadPlus m => m a -> m [a] many (m a p m a -> (a -> m a) -> m a forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>=\a x ->a x a -> m sep -> m a forall (f :: * -> *) a b. Functor f => a -> f b -> f a <$m sep sep ){-# INLINEendBy #-}-- | @'endBy1' p sep@ parses /one/ or more occurrences of @p@, separated and-- ended by @sep@. Returns a list of values returned by @p@.endBy1 ::MonadPlusm =>m a ->m sep ->m [a ]endBy1 :: m a -> m sep -> m [a] endBy1 m a p m sep sep =m a -> m [a] forall (m :: * -> *) a. MonadPlus m => m a -> m [a] some (m a p m a -> (a -> m a) -> m a forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>=\a x ->a x a -> m sep -> m a forall (f :: * -> *) a b. Functor f => a -> f b -> f a <$m sep sep ){-# INLINEendBy1 #-}-- | @'many' p@ applies the parser @p@ /zero/ or more times and returns a-- list of the values returned by @p@.---- > identifier = (:) <$> letter <*> many (alphaNumChar <|> char '_')many ::MonadPlusm =>m a ->m [a ]many :: m a -> m [a] many m a p =([a] -> [a]) -> m [a] forall c. ([a] -> c) -> m c go [a] -> [a] forall a. a -> a idwherego :: ([a] -> c) -> m c go [a] -> c f =doMaybe a r <-m a -> m (Maybe a) forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a) C.optionalm a p caseMaybe a r ofMaybe a Nothing->c -> m c forall (m :: * -> *) a. Monad m => a -> m a return([a] -> c f [])Justa x ->([a] -> c) -> m c go ([a] -> c f ([a] -> c) -> ([a] -> [a]) -> [a] -> c forall b c a. (b -> c) -> (a -> b) -> a -> c .(a x a -> [a] -> [a] forall a. a -> [a] -> [a] :)){-# INLINEmany #-}-- | @'manyTill' p end@ applies parser @p@ /zero/ or more times until parser-- @end@ succeeds. Returns the list of values returned by @p@. __Note__ that-- @end@ result is consumed and lost. Use 'manyTill_' if you wish to keep-- it.---- See also: 'skipMany', 'skipManyTill'.manyTill ::MonadPlusm =>m a ->m end ->m [a ]manyTill :: m a -> m end -> m [a] manyTill m a p m end end =([a], end) -> [a] forall a b. (a, b) -> a fst(([a], end) -> [a]) -> m ([a], end) -> m [a] forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$>m a -> m end -> m ([a], end) forall (m :: * -> *) a end. MonadPlus m => m a -> m end -> m ([a], end) manyTill_ m a p m end end {-# INLINEmanyTill #-}-- | @'manyTill_' p end@ applies parser @p@ /zero/ or more times until-- parser @end@ succeeds. Returns the list of values returned by @p@ and the-- @end@ result. Use 'manyTill' if you have no need in the result of the-- @end@.---- See also: 'skipMany', 'skipManyTill'.---- @since 1.2.0manyTill_ ::MonadPlusm =>m a ->m end ->m ([a ],end )manyTill_ :: m a -> m end -> m ([a], end) manyTill_ m a p m end end =([a] -> [a]) -> m ([a], end) forall c. ([a] -> c) -> m (c, end) go [a] -> [a] forall a. a -> a idwherego :: ([a] -> c) -> m (c, end) go [a] -> c f =doMaybe end done <-m end -> m (Maybe end) forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a) C.optionalm end end caseMaybe end done ofJustend done' ->(c, end) -> m (c, end) forall (m :: * -> *) a. Monad m => a -> m a return([a] -> c f [],end done' )Maybe end Nothing->doa x <-m a p ([a] -> c) -> m (c, end) go ([a] -> c f ([a] -> c) -> ([a] -> [a]) -> [a] -> c forall b c a. (b -> c) -> (a -> b) -> a -> c .(a x a -> [a] -> [a] forall a. a -> [a] -> [a] :)){-# INLINEmanyTill_ #-}-- | @'some' p@ applies the parser @p@ /one/ or more times and returns a-- list of the values returned by @p@.---- > word = some lettersome ::MonadPlusm =>m a ->m [a ]some :: m a -> m [a] some m a p =(a -> [a] -> [a]) -> m a -> m [a] -> m [a] forall (m :: * -> *) a1 a2 r. Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r liftM2(:)m a p (m a -> m [a] forall (m :: * -> *) a. MonadPlus m => m a -> m [a] many m a p ){-# INLINEsome #-}-- | @'someTill' p end@ works similarly to @'manyTill' p end@, but @p@-- should succeed at least once. __Note__ that @end@ result is consumed and-- lost. Use 'someTill_' if you wish to keep it.---- > someTill p end = liftM2 (:) p (manyTill p end)---- See also: 'skipSome', 'skipSomeTill'.someTill ::MonadPlusm =>m a ->m end ->m [a ]someTill :: m a -> m end -> m [a] someTill m a p m end end =(a -> [a] -> [a]) -> m a -> m [a] -> m [a] forall (m :: * -> *) a1 a2 r. Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r liftM2(:)m a p (m a -> m end -> m [a] forall (m :: * -> *) a end. MonadPlus m => m a -> m end -> m [a] manyTill m a p m end end ){-# INLINEsomeTill #-}-- | @'someTill_' p end@ works similarly to @'manyTill_' p end@, but @p@-- should succeed at least once. Use 'someTill' if you have no need in the-- result of the @end@.---- See also: 'skipSome', 'skipSomeTill'.---- @since 1.2.0someTill_ ::MonadPlusm =>m a ->m end ->m ([a ],end )someTill_ :: m a -> m end -> m ([a], end) someTill_ m a p m end end =(a -> ([a], end) -> ([a], end)) -> m a -> m ([a], end) -> m ([a], end) forall (m :: * -> *) a1 a2 r. Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r liftM2(\a x ([a] xs ,end y )->(a x a -> [a] -> [a] forall a. a -> [a] -> [a] :[a] xs ,end y ))m a p (m a -> m end -> m ([a], end) forall (m :: * -> *) a end. MonadPlus m => m a -> m end -> m ([a], end) manyTill_ m a p m end end ){-# INLINEsomeTill_ #-}-- | @'sepBy' p sep@ parses /zero/ or more occurrences of @p@, separated by-- @sep@. Returns a list of values returned by @p@.---- > commaSep p = p `sepBy` commasepBy ::MonadPlusm =>m a ->m sep ->m [a ]sepBy :: m a -> m sep -> m [a] sepBy m a p m sep sep =doMaybe a r <-m a -> m (Maybe a) forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a) C.optionalm a p caseMaybe a r ofMaybe a Nothing->[a] -> m [a] forall (m :: * -> *) a. Monad m => a -> m a return[]Justa x ->(a x a -> [a] -> [a] forall a. a -> [a] -> [a] :)([a] -> [a]) -> m [a] -> m [a] forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$>m a -> m [a] forall (m :: * -> *) a. MonadPlus m => m a -> m [a] many (m sep sep m sep -> m a -> m a forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >>m a p ){-# INLINEsepBy #-}-- | @'sepBy1' p sep@ parses /one/ or more occurrences of @p@, separated by-- @sep@. Returns a list of values returned by @p@.sepBy1 ::MonadPlusm =>m a ->m sep ->m [a ]sepBy1 :: m a -> m sep -> m [a] sepBy1 m a p m sep sep =doa x <-m a p (a x a -> [a] -> [a] forall a. a -> [a] -> [a] :)([a] -> [a]) -> m [a] -> m [a] forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$>m a -> m [a] forall (m :: * -> *) a. MonadPlus m => m a -> m [a] many (m sep sep m sep -> m a -> m a forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >>m a p ){-# INLINEsepBy1 #-}-- | @'sepEndBy' p sep@ parses /zero/ or more occurrences of @p@, separated-- and optionally ended by @sep@. Returns a list of values returned by @p@.sepEndBy ::MonadPlusm =>m a ->m sep ->m [a ]sepEndBy :: m a -> m sep -> m [a] sepEndBy m a p m sep sep =([a] -> [a]) -> m [a] forall a. ([a] -> a) -> m a go [a] -> [a] forall a. a -> a idwherego :: ([a] -> a) -> m a go [a] -> a f =doMaybe a r <-m a -> m (Maybe a) forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a) C.optionalm a p caseMaybe a r ofMaybe a Nothing->a -> m a forall (m :: * -> *) a. Monad m => a -> m a return([a] -> a f [])Justa x ->doBool more <-Bool -> m Bool -> m Bool forall (m :: * -> *) a. Alternative m => a -> m a -> m a C.option Bool False(Bool TrueBool -> m sep -> m Bool forall (f :: * -> *) a b. Functor f => a -> f b -> f a <$m sep sep )ifBool more then([a] -> a) -> m a go ([a] -> a f ([a] -> a) -> ([a] -> [a]) -> [a] -> a forall b c a. (b -> c) -> (a -> b) -> a -> c .(a x a -> [a] -> [a] forall a. a -> [a] -> [a] :))elsea -> m a forall (m :: * -> *) a. Monad m => a -> m a return([a] -> a f [a x ]){-# INLINEsepEndBy #-}-- | @'sepEndBy1' p sep@ parses /one/ or more occurrences of @p@, separated-- and optionally ended by @sep@. Returns a list of values returned by @p@.sepEndBy1 ::MonadPlusm =>m a ->m sep ->m [a ]sepEndBy1 :: m a -> m sep -> m [a] sepEndBy1 m a p m sep sep =doa x <-m a p Bool more <-Bool -> m Bool -> m Bool forall (m :: * -> *) a. Alternative m => a -> m a -> m a C.option Bool False(Bool TrueBool -> m sep -> m Bool forall (f :: * -> *) a b. Functor f => a -> f b -> f a <$m sep sep )ifBool more then(a x a -> [a] -> [a] forall a. a -> [a] -> [a] :)([a] -> [a]) -> m [a] -> m [a] forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$>m a -> m sep -> m [a] forall (m :: * -> *) a end. MonadPlus m => m a -> m end -> m [a] sepEndBy m a p m sep sep else[a] -> m [a] forall (m :: * -> *) a. Monad m => a -> m a return[a x ]{-# INLINEsepEndBy1 #-}-- | @'skipMany' p@ applies the parser @p@ /zero/ or more times, skipping-- its result.---- See also: 'manyTill', 'skipManyTill'.skipMany ::MonadPlusm =>m a ->m ()skipMany :: m a -> m () skipMany m a p =m () go wherego :: m () go =doBool more <-Bool -> m Bool -> m Bool forall (m :: * -> *) a. Alternative m => a -> m a -> m a C.option Bool False(Bool TrueBool -> m a -> m Bool forall (f :: * -> *) a b. Functor f => a -> f b -> f a <$m a p )Bool -> m () -> m () forall (f :: * -> *). Applicative f => Bool -> f () -> f () whenBool more m () go {-# INLINEskipMany #-}-- | @'skipSome' p@ applies the parser @p@ /one/ or more times, skipping its-- result.---- See also: 'someTill', 'skipSomeTill'.skipSome ::MonadPlusm =>m a ->m ()skipSome :: m a -> m () skipSome m a p =m a p m a -> m () -> m () forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >>m a -> m () forall (m :: * -> *) a. MonadPlus m => m a -> m () skipMany m a p {-# INLINEskipSome #-}-- | @'skipCount' n p@ parses @n@ occurrences of @p@, skipping its result.-- If @n@ is smaller or equal to zero, the parser equals to @'return' ()@.---- See also: 'count', 'count''.skipCount ::Monadm =>Int->m a ->m ()skipCount :: Int -> m a -> m () skipCount Int n' m a p =Int -> m () forall t. (Ord t, Num t) => t -> m () go Int n' wherego :: t -> m () go !t n =Bool -> m () -> m () forall (f :: * -> *). Applicative f => Bool -> f () -> f () unless(t n t -> t -> Bool forall a. Ord a => a -> a -> Bool <=t 0)(m () -> m ()) -> m () -> m () forall a b. (a -> b) -> a -> b $m a p m a -> m () -> m () forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >>t -> m () go (t n t -> t -> t forall a. Num a => a -> a -> a -t 1){-# INLINEskipCount #-}-- | @'skipManyTill' p end@ applies the parser @p@ /zero/ or more times-- skipping results until parser @end@ succeeds. Result parsed by @end@ is-- then returned.---- See also: 'manyTill', 'skipMany'.skipManyTill ::MonadPlusm =>m a ->m end ->m end skipManyTill :: m a -> m end -> m end skipManyTill m a p m end end =m end go wherego :: m end go =doMaybe end r <-m end -> m (Maybe end) forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a) C.optionalm end end caseMaybe end r ofMaybe end Nothing->m a p m a -> m end -> m end forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >>m end go Justend x ->end -> m end forall (m :: * -> *) a. Monad m => a -> m a returnend x {-# INLINEskipManyTill #-}-- | @'skipSomeTill' p end@ applies the parser @p@ /one/ or more times-- skipping results until parser @end@ succeeds. Result parsed by @end@ is-- then returned.---- See also: 'someTill', 'skipSome'.skipSomeTill ::MonadPlusm =>m a ->m end ->m end skipSomeTill :: m a -> m end -> m end skipSomeTill m a p m end end =m a p m a -> m end -> m end forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >>m a -> m end -> m end forall (m :: * -> *) a end. MonadPlus m => m a -> m end -> m end skipManyTill m a p m end end {-# INLINEskipSomeTill #-}