@@ -203,7 +203,8 @@ where
204import Control.Applicative (Alternative(..), liftA2)
204import Control.Applicative (Alternative(..), liftA2)
205import Control.Exception (Exception(..))
205import Control.Exception (Exception(..))
206−import Control.Monad (MonadPlus(..), (>=>))
206+-- import Control.Monad (MonadPlus(..), (>=>))
207+import Control.Monad ((>=>))
207import Control.Monad.IO.Class (MonadIO, liftIO)
208import Control.Monad.IO.Class (MonadIO, liftIO)
208import Data.Bifunctor (Bifunctor(..))
209import Data.Bifunctor (Bifunctor(..))
209import Fusion.Plugin.Types (Fuse(..))
210import Fusion.Plugin.Types (Fuse(..))
@@ -218,7 +219,9 @@ import Prelude hiding (concatMap, filter)
219-- >>> import Control.Applicative ((<|>))
220-- >>> import Control.Applicative ((<|>))
220-- >>> import Data.Bifunctor (second)
221-- >>> import Data.Bifunctor (second)
221−-- >>> import Prelude hiding (concatMap)
222+-- >>> import Prelude hiding (concatMap, span)
223+-- >>> import Streamly.Data.Fold (Fold)
224+-- >>> import Streamly.Data.Parser (Parser)
222-- >>> import qualified Streamly.Data.Fold as Fold
225-- >>> import qualified Streamly.Data.Fold as Fold
223-- >>> import qualified Streamly.Data.Stream as Stream
226-- >>> import qualified Streamly.Data.Stream as Stream
224-- >>> import qualified Streamly.Internal.Data.Stream as Stream (parse)
227-- >>> import qualified Streamly.Internal.Data.Stream as Stream (parse)
@@ -492,16 +495,17 @@ data SeqParseState sl f sr = SeqParseL !sl | SeqParseR !f !sr
492-- cannot scale to a large number of compositions. After around 100
495-- cannot scale to a large number of compositions. After around 100
493-- compositions the performance starts dipping rapidly beyond a CPS style
496-- compositions the performance starts dipping rapidly beyond a CPS style
494-- unfused implementation.
497-- unfused implementation.
496−-- | Sequential parser application. Apply two parsers sequentially to an input
497−-- stream. The input is provided to the first parser, when it is done the
498−-- remaining input is provided to the second parser. If both the parsers
499−-- succeed their outputs are combined using the supplied function. The
500−-- operation fails if any of the parsers fail.
502-- Note: This is a parsing dual of appending streams using
499-- Note: This is a parsing dual of appending streams using
503−-- 'Streamly.Data.Stream.append', it splits the streams using two parsers and zips
500+-- 'Streamly.Data.Stream.append', it splits the streams using two parsers and
504−-- the results.
501+-- zips the results.
503+-- | Sequential parser application.
505+-- Apply two parsers sequentially to an input stream. The first parser runs and
506+-- processes the input, the remaining input is then passed to the second
507+-- parser. If both parsers succeed, their outputs are combined using the
508+-- supplied function. If either parser fails, the operation fails.
506-- This implementation is strict in the second argument, therefore, the
510-- This implementation is strict in the second argument, therefore, the
507-- following will fail:
511-- following will fail:
@@ -510,28 +514,15 @@ data SeqParseState sl f sr = SeqParseL !sl | SeqParseR !f !sr
510-- *** Exception: Prelude.undefined
514-- *** Exception: Prelude.undefined
513−-- Compare with 'Applicative' instance method '<*>'. This implementation allows
514−-- stream fusion but has quadratic complexity. This can fuse with other
517+-- Although this implementation allows stream fusion, it has quadratic
515−-- operations and can be faster than 'Applicative' instance for small number
518+-- complexity, making it suitable only for a small number of compositions.
516−-- (less than 8) of compositions.
519+-- As a thumb rule use it for less than 8 compositions, use ParserK otherwise.
518−-- Many combinators can be expressed using @splitWith@ and other parser
519−-- primitives. Some common idioms are described below,
521−-- @
521+-- Below are some common idioms that can be expressed using 'splitWith' and
522−-- span :: (a -> Bool) -> Fold m a b -> Fold m a b -> Parser a m b
522+-- other parser primitives:
523−-- span pred f1 f2 = splitWith (,) ('takeWhile' pred f1) ('fromFold' f2)
526−-- @
524+-- >>> span p f1 f2 = Parser.splitWith (,) (Parser.takeWhile p f1) (Parser.fromFold f2)
527−-- spanBy :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser a m b
528−-- spanBy eq f1 f2 = splitWith (,) ('groupBy' eq f1) ('fromFold' f2)
525+-- >>> spanBy eq f1 f2 = Parser.splitWith (,) (Parser.groupBy eq f1) (Parser.fromFold f2)
532−-- spanByRolling :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser a m b
533−-- spanByRolling eq f1 f2 = splitWith (,) ('groupByRolling' eq f1) ('fromFold' f2)
536-- /Pre-release/
527-- /Pre-release/
@@ -695,10 +686,9 @@ data SeqAState sl sr = SeqAL !sl | SeqAR !sr
695-- *** Exception: Prelude.undefined
686-- *** Exception: Prelude.undefined
698−-- Compare with 'Applicative' instance method '*>'. This implementation allows
699−-- stream fusion but has quadratic complexity. This can fuse with other
689+-- Although this implementation allows stream fusion, it has quadratic
700−-- operations, and can be faster than 'Applicative' instance for small
690+-- complexity, making it suitable only for a small number of compositions.
701−-- number (less than 8) of compositions.
691+-- As a thumb rule use it for less than 8 compositions, use ParserK otherwise.
703-- /Pre-release/
693-- /Pre-release/
@@ -836,9 +826,10 @@ data AltParseState sl sr = AltParseL !Int !sl | AltParseR !sr
836-- each subsequent alternative's input element has to go through, therefore, it
826-- each subsequent alternative's input element has to go through, therefore, it
837-- cannot scale to a large number of compositions
827-- cannot scale to a large number of compositions
839−-- | Sequential alternative. Apply the input to the first parser and return the
829+-- | Sequential alternative. The input is first passed to the first parser, and
840−-- result if the parser succeeds. If the first parser fails then backtrack and
830+-- if it succeeds, the result is returned. However, if the first parser fails,
841−-- apply the same input to the second parser and return the result.
831+-- the parser driver backtracks and tries the same input on the second parser,
832+-- returning the result if it succeeds.
843-- Note: This implementation is not lazy in the second argument. The following
834-- Note: This implementation is not lazy in the second argument. The following
844-- will fail:
835-- will fail:
@@ -846,10 +837,9 @@ data AltParseState sl sr = AltParseL !Int !sl | AltParseR !sr
846-- >> Stream.parse (Parser.satisfy (> 0) `Parser.alt` undefined) $ Stream.fromList [1..10]
837-- >> Stream.parse (Parser.satisfy (> 0) `Parser.alt` undefined) $ Stream.fromList [1..10]
847-- *** Exception: Prelude.undefined
838-- *** Exception: Prelude.undefined
849−-- Compare with ParserK 'Alternative' instance method '<|>'. This
850−-- implementation allows stream fusion but has quadratic complexity. This can
840+-- Although this implementation allows stream fusion, it has quadratic
851−-- fuse with other operations and can be much faster than 'Alternative'
841+-- complexity, making it suitable only for a small number of compositions.
852−-- instance for small number (less than 8) of alternatives.
842+-- As a thumb rule use it for less than 8 compositions, use ParserK otherwise.
854-- /Time Complexity:/ O(n^2) where n is the number of compositions.
844-- /Time Complexity:/ O(n^2) where n is the number of compositions.
@@ -1179,7 +1169,10 @@ dieM err = Parser undefined (IError <$> err) undefined
1179-- Note: With the direct style parser type, the list in "some" and "many" is
1169-- Note: With the direct style parser type, the list in "some" and "many" is
1180-- accumulated strictly, it cannot be consumed lazily.
1170-- accumulated strictly, it cannot be consumed lazily.
1182−-- | 'Alternative' instance using 'alt'.
1172+-- | Sequential alternative. The input is first passed to the first parser, and
1173+-- if it succeeds, the result is returned. However, if the first parser fails,
1174+-- the parser driver backtracks and tries the same input on the second parser,
1175+-- returning the result if it succeeds.
1184-- Note: The implementation of '<|>' is not lazy in the second
1177-- Note: The implementation of '<|>' is not lazy in the second
1185-- argument. The following code will fail:
1178-- argument. The following code will fail:
@@ -1188,6 +1181,11 @@ dieM err = Parser undefined (IError <$> err) undefined
1188-- *** Exception: Prelude.undefined
1181-- *** Exception: Prelude.undefined
1184+-- WARNING! this is not suitable for large scale use. As a thumb rule stream
1185+-- fusion works well for less than 8 compositions of this operation, otherwise
1186+-- consider using 'ParserK'. Do not use recursive parser implementations based
1187+-- on this Alternative instance.
1191instance Monad m => Alternative (Parser a m) where
1189instance Monad m => Alternative (Parser a m) where
1192 {-# INLINE empty #-}
1190 {-# INLINE empty #-}
1193 empty = die "empty"
1191 empty = die "empty"
@@ -1351,6 +1349,10 @@ noErrorUnsafeConcatMap func (Parser stepL initialL extractL) =
1352-- | See documentation of 'Streamly.Internal.Data.Parser.ParserK.Type.Parser'.
1350-- | See documentation of 'Streamly.Internal.Data.Parser.ParserK.Type.Parser'.
1352+-- Although this implementation allows stream fusion, it has quadratic
1353+-- complexity, making it suitable only for a small number of compositions. As a
1354+-- thumb rule use it for less than 8 compositions, use 'ParserK' otherwise.
1354instance Monad m => Monad (Parser a m) where
1356instance Monad m => Monad (Parser a m) where
1355 {-# INLINE return #-}
1357 {-# INLINE return #-}
1356 return = pure
1358 return = pure
@@ -1365,6 +1367,7 @@ instance Monad m => Fail.MonadFail (Parser a m) where
1365 {-# INLINE fail #-}
1367 {-# INLINE fail #-}
1366 fail = die
1368 fail = die
1368-- | See documentation of 'Streamly.Internal.Data.Parser.ParserK.Type.Parser'.
1371-- | See documentation of 'Streamly.Internal.Data.Parser.ParserK.Type.Parser'.
1370instance Monad m => MonadPlus (Parser a m) where
1373instance Monad m => MonadPlus (Parser a m) where
@@ -1373,6 +1376,7 @@ instance Monad m => MonadPlus (Parser a m) where
1374 {-# INLINE mplus #-}
1377 {-# INLINE mplus #-}
1375 mplus = alt
1378 mplus = alt
1377instance (Monad m, MonadIO m) => MonadIO (Parser a m) where
1381instance (Monad m, MonadIO m) => MonadIO (Parser a m) where
1378 {-# INLINE liftIO #-}
1382 {-# INLINE liftIO #-}