3-- Module : Streamly.Data.ParserK
4-- Copyright : (c) 2023 Composewell Technologies
5-- License : BSD-3-Clause
6-- Maintainer : streamly@composewell.com
7-- Stability : pre-release
10-- See the general notes about parsing in the "Streamly.Data.Parser" module.
11-- This module implements a using Continuation Passing Style (CPS) wrapper over
12-- the "Streamly.Data.Parser" module. It is as fast or faster than attoparsec.
14-- == Parser vs ParserK
16-- 'ParserK' is preferred over 'Streamly.Data.Parser.Parser' when extensive
17-- applicative, alternative and monadic composition is required, or when
18-- recursive or dynamic composition of parsers is required. The
19-- 'Streamly.Data.Parser.Parser' type fuses statically and creates efficient
20-- loops whereas 'ParserK' uses function call based composition and has
21-- comparatively larger runtime overhead but it is better suited to the
22-- specific use cases mentioned above. 'ParserK' also allows to efficient parse
23-- a stream of arrays, it can also break the input stream into a parse result
24-- and remaining stream so that the stream can be parsed independently in
29-- All the parsers from the "Streamly.Data.Parser" module can be adapted to
30-- ParserK using the 'Streamly.Data.ParserK.adaptC',
31-- 'Streamly.Internal.Data.ParserK.adapt', and
32-- 'Streamly.Internal.Data.ParserK.adaptCG' combinators.
34-- 'Streamly.Data.StreamK.parseChunks' runs a parser on a stream of unboxed
35-- arrays, this is the preferred and most efficient way to parse chunked input.
36-- The more general 'Streamly.Data.StreamK.parseBreakChunks' function returns
37-- the remaining stream as well along with the parse result. There are
38-- 'Streamly.Internal.Data.StreamK.parseChunksGeneric',
39-- 'Streamly.Internal.Data.StreamK.parseBreakChunksGeneric' as well to run
40-- parsers on boxed arrays. 'Streamly.Internal.Data.StreamK.parse',
41-- 'Streamly.Internal.Data.StreamK.parseBreak' run parsers on a stream of
42-- individual elements instead of stream of arrays.
44-- == Monadic Composition
46-- Monad composition can be used for lookbehind parsers, we can dynamically
47-- compose new parsers based on the results of the previously parsed values.
49-- If we have to parse "a9" or "9a" but not "99" or "aa" we can use the
50-- following non-monadic, backtracking parser:
52-- >>> digits p1 p2 = ((:) <$> p1 <*> ((:) <$> p2 <*> pure []))
54-- backtracking :: Monad m => ParserK Char m String
55-- backtracking = ParserK.adapt $
56-- digits (Parser.satisfy isDigit) (Parser.satisfy isAlpha)
58-- digits (Parser.satisfy isAlpha) (Parser.satisfy isDigit)
61-- We know that if the first parse resulted in a digit at the first place then
62-- the second parse is going to fail. However, we waste that information and
63-- parse the first character again in the second parse only to know that it is
64-- not an alphabetic char. By using lookbehind in a 'Monad' composition we can
65-- avoid redundant work:
67-- >>> data DigitOrAlpha = Digit Char | Alpha Char
70-- lookbehind :: Monad m => ParserK Char m String
72-- x1 <- ParserK.adapt $
73-- Digit <$> Parser.satisfy isDigit
74-- <|> Alpha <$> Parser.satisfy isAlpha
75-- -- Note: the parse depends on what we parsed already
76-- x2 <- ParserK.adapt $
78-- Digit _ -> Parser.satisfy isAlpha
79-- Alpha _ -> Parser.satisfy isDigit
85-- == Experimental APIs
87-- Please refer to "Streamly.Internal.Data.ParserK" for functions that have
88-- not yet been released.
90module Streamly.Data.ParserK
93 -- | To execute the code examples provided in this module in ghci, please
94 -- run the following commands first.
120import Control.Monad.IO.Class (MonadIO)
121import Streamly.Internal.Data.Fold (Fold)
122import Streamly.Internal.Data.Unbox (Unbox)
123import Streamly.Internal.Data.Array (Array)
124import qualified Streamly.Internal.Data.Parser as ParserD
126import Streamly.Internal.Data.ParserK.Type
128#include "DocTestDataParserK.hs"
130{-# DEPRECATED fromFold "Please use \"ParserK.adaptC . Parser.fromFold\" instead." #-}
131{-# INLINE fromFold #-}
132fromFold :: (MonadIO m, Unbox a) => Fold m a b -> ParserK (Array a) m b
133fromFold = adaptC . ParserD.fromFold
135{-# DEPRECATED fromParser "Please use \"adaptC\" instead." #-}
136{-# INLINE fromParser #-}
138 (MonadIO m, Unbox a) => ParserD.Parser a m b -> ParserK (Array a) m b
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list