polyparse-1.4.1: docs/haddock/src/Text/ParserCombinators/Poly/Base.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<pre><a name="line-1"></a><font color=Green><u>module</u></font> Text<font color=Cyan>.</font>ParserCombinators<font color=Cyan>.</font>Poly<font color=Cyan>.</font>Base
<a name="line-2"></a> <font color=Cyan>(</font> <font color=Blue>-- * The PolyParse class</font>
<a name="line-3"></a> PolyParse<font color=Cyan>(</font><font color=Red>..</font><font color=Cyan>)</font> <font color=Blue>-- class of all monadic two-level-error parsers</font>
<a name="line-4"></a>
<a name="line-5"></a> <font color=Blue>-- * Combinators general to all parser types.</font>
<a name="line-6"></a> <font color=Blue>-- ** Simple combinators</font>
<a name="line-7"></a> <font color=Cyan>,</font> discard <font color=Blue>-- :: PolyParse p => p a -> p b -> p a</font>
<a name="line-8"></a> <font color=Blue>-- ** Error-handling</font>
<a name="line-9"></a> <font color=Cyan>,</font> failBad <font color=Blue>-- :: PolyParse p => String -> p a</font>
<a name="line-10"></a> <font color=Cyan>,</font> adjustErrBad<font color=Blue>-- :: PolyParse p => p a -> (String->String) -> p a</font>
<a name="line-11"></a> <font color=Cyan>,</font> indent <font color=Blue>-- :: Int -> String -> String</font>
<a name="line-12"></a> <font color=Blue>-- ** Choices</font>
<a name="line-13"></a> <font color=Cyan>,</font> oneOf <font color=Blue>-- :: PolyParse p => [p a] -> p a</font>
<a name="line-14"></a> <font color=Cyan>,</font> optional <font color=Blue>-- :: PolyParse p => p a -> p (Maybe a)</font>
<a name="line-15"></a> <font color=Blue>-- ** Sequences</font>
<a name="line-16"></a> <font color=Cyan>,</font> exactly <font color=Blue>-- :: PolyParse p => Int -> p a -> p [a]</font>
<a name="line-17"></a> <font color=Cyan>,</font> many <font color=Blue>-- :: PolyParse p => p a -> p [a]</font>
<a name="line-18"></a> <font color=Cyan>,</font> many1 <font color=Blue>-- :: PolyParse p => p a -> p [a]</font>
<a name="line-19"></a> <font color=Cyan>,</font> sepBy <font color=Blue>-- :: PolyParse p => p a -> p sep -> p [a]</font>
<a name="line-20"></a> <font color=Cyan>,</font> sepBy1 <font color=Blue>-- :: PolyParse p => p a -> p sep -> p [a]</font>
<a name="line-21"></a> <font color=Cyan>,</font> bracketSep <font color=Blue>-- :: PolyParse p => p bra -> p sep -> p ket -> p a -> p [a]</font>
<a name="line-22"></a> <font color=Cyan>,</font> bracket <font color=Blue>-- :: PolyParse p => p bra -> p ket -> p a -> p a</font>
<a name="line-23"></a> <font color=Cyan>,</font> manyFinally <font color=Blue>-- :: PolyParse p => p a -> p z -> p [a]</font>
<a name="line-24"></a> <font color=Cyan>)</font> <font color=Green><u>where</u></font>
<a name="line-25"></a>
<a name="line-26"></a><font color=Magenta><em>#ifdef __NHC__</em></font>
<a name="line-27"></a><font color=Green><u>default</u></font> <font color=Cyan>(</font>Integer<font color=Cyan>,</font>Double<font color=Cyan>,</font>[]<font color=Cyan>)</font> <font color=Blue>-- hack to avoid bizarre type defaulting error</font>
<a name="line-28"></a><font color=Green><u>instance</u></font> PolyParse []
<a name="line-29"></a><font color=Magenta><em>#endif</em></font>
<a name="line-30"></a>
<a name="line-31"></a><a name="PolyParse"></a><font color=Blue>-- | The @PolyParse@ class is an abstraction over all the current</font>
<a name="line-32"></a><a name="PolyParse"></a><font color=Blue>-- concrete representations of monadic parser combinators in this</font>
<a name="line-33"></a><a name="PolyParse"></a><font color=Blue>-- package. The common feature is two-level error-handling.</font>
<a name="line-34"></a><a name="PolyParse"></a><font color=Blue>-- Some primitives must be implemented specific to each parser type</font>
<a name="line-35"></a><a name="PolyParse"></a><font color=Blue>-- (e.g. depending on whether the parser has a running state, or</font>
<a name="line-36"></a><a name="PolyParse"></a><font color=Blue>-- whether it is lazy). But given those primitives, large numbers of</font>
<a name="line-37"></a><a name="PolyParse"></a><font color=Blue>-- combinators do not depend any further on the internal structure of</font>
<a name="line-38"></a><a name="PolyParse"></a><font color=Blue>-- the particular parser.</font>
<a name="line-39"></a><a name="PolyParse"></a><font color=Blue>--</font>
<a name="line-40"></a><a name="PolyParse"></a><font color=Blue>-- There are two additional basic combinators that we expect to be implemented</font>
<a name="line-41"></a><a name="PolyParse"></a><font color=Blue>-- afresh for every concrete type, but which (for technical reasons)</font>
<a name="line-42"></a><a name="PolyParse"></a><font color=Blue>-- cannot be class methods. They are @next@ and @satisfy@.</font>
<a name="line-43"></a><a name="PolyParse"></a><font color=Green><u>class</u></font> <font color=Cyan>(</font>Functor p<font color=Cyan>,</font> Monad p<font color=Cyan>)</font> <font color=Red>=></font> PolyParse p <font color=Green><u>where</u></font>
<a name="line-44"></a> <font color=Blue>-- | Commit is a way of raising the severity of any errors found within</font>
<a name="line-45"></a> <font color=Blue>-- its argument. Used in the middle of a parser definition, it means that</font>
<a name="line-46"></a> <font color=Blue>-- any operations prior to commitment fail softly, but after commitment,</font>
<a name="line-47"></a> <font color=Blue>-- they fail hard.</font>
<a name="line-48"></a> commit <font color=Red>::</font> p a <font color=Red>-></font> p a
<a name="line-49"></a> <font color=Blue>-- | @p `adjustErr` f@ applies the transformation @f@ to any error message</font>
<a name="line-50"></a> <font color=Blue>-- generated in @p@, having no effect if @p@ succeeds.</font>
<a name="line-51"></a> adjustErr <font color=Red>::</font> p a <font color=Red>-></font> <font color=Cyan>(</font>String <font color=Red>-></font> String<font color=Cyan>)</font> <font color=Red>-></font> p a
<a name="line-52"></a> <font color=Blue>-- | @p `onFail` q@ means parse p, unless p fails, in which case</font>
<a name="line-53"></a> <font color=Blue>-- parse q instead.</font>
<a name="line-54"></a> <font color=Blue>-- Can be chained together to give multiple attempts to parse something.</font>
<a name="line-55"></a> <font color=Blue>-- (Note that q could itself be a failing parser, e.g. to change the error</font>
<a name="line-56"></a> <font color=Blue>-- message from that defined in p to something different.)</font>
<a name="line-57"></a> <font color=Blue>-- However, a severe failure in p cannot be ignored.</font>
<a name="line-58"></a> onFail <font color=Red>::</font> p a <font color=Red>-></font> p a <font color=Red>-></font> p a
<a name="line-59"></a> <font color=Blue>-- | Parse the first alternative that succeeds, but if none succeed,</font>
<a name="line-60"></a> <font color=Blue>-- report only the severe errors, and if none of those, then report</font>
<a name="line-61"></a> <font color=Blue>-- all the soft errors.</font>
<a name="line-62"></a> oneOf' <font color=Red>::</font> <font color=Red>[</font><font color=Cyan>(</font>String<font color=Cyan>,</font> p a<font color=Cyan>)</font><font color=Red>]</font> <font color=Red>-></font> p a
<a name="line-63"></a> <font color=Blue>-- | Apply a parsed function to a parsed value.</font>
<a name="line-64"></a> <font color=Blue>-- Rather like ordinary function application lifted into parsers.</font>
<a name="line-65"></a> apply <font color=Red>::</font> p <font color=Cyan>(</font>a<font color=Red>-></font>b<font color=Cyan>)</font> <font color=Red>-></font> p a <font color=Red>-></font> p b
<a name="line-66"></a> pf <font color=Cyan>`apply`</font> px <font color=Red>=</font> <font color=Green><u>do</u></font> <font color=Cyan>{</font> f <font color=Red><-</font> pf<font color=Cyan>;</font> x <font color=Red><-</font> px<font color=Cyan>;</font> return <font color=Cyan>(</font>f x<font color=Cyan>)</font> <font color=Cyan>}</font>
<a name="line-67"></a> <font color=Blue>-- note: the Poly.Lazy variants override this defn with a lazier one.</font>
<a name="line-68"></a>
<a name="line-69"></a><font color=Green><u>infixl</u></font> <font color=Magenta>6</font> <font color=Cyan>`onFail`</font> <font color=Blue>-- not sure about precedence 6?</font>
<a name="line-70"></a><font color=Green><u>infixl</u></font> <font color=Magenta>3</font> <font color=Cyan>`apply`</font>
<a name="line-71"></a><font color=Green><u>infixl</u></font> <font color=Magenta>3</font> <font color=Cyan>`discard`</font>
<a name="line-72"></a>
<a name="line-73"></a><font color=Blue>{-
<a name="line-74"></a>-- Combinators we expect most concrete parser types to implement.
<a name="line-75"></a>-- For technical reasons, they cannot be class members.
<a name="line-76"></a>
<a name="line-77"></a>-- | Yield the next token
<a name="line-78"></a>next :: PolyParse p => p t
<a name="line-79"></a> -- where t is constrained to be the input token type
<a name="line-80"></a>
<a name="line-81"></a>-- | One token satisfying a predicate.
<a name="line-82"></a>satisfy :: PolyParse p => (t->Bool) -> p t t
<a name="line-83"></a>satisfy p = do{ x <- next
<a name="line-84"></a> ; if p x then return x else fail "Parse.satisfy: failed"
<a name="line-85"></a> }
<a name="line-86"></a> -- note: must be re-defined for each implementation because
<a name="line-87"></a> -- its type cannot be expressed otherwise.
<a name="line-88"></a>-}</font>
<a name="line-89"></a>
<a name="line-90"></a><a name="failBad"></a><font color=Blue>-- | When a simple fail is not strong enough, use failBad for emphasis.</font>
<a name="line-91"></a><font color=Blue>-- An emphasised (severe) error cannot be overridden by choice</font>
<a name="line-92"></a><font color=Blue>-- operators.</font>
<a name="line-93"></a><font color=Blue>failBad</font> <font color=Red>::</font> PolyParse p <font color=Red>=></font> String <font color=Red>-></font> p a
<a name="line-94"></a><font color=Blue>failBad</font> e <font color=Red>=</font> commit <font color=Cyan>(</font>fail e<font color=Cyan>)</font>
<a name="line-95"></a>
<a name="line-96"></a><a name="discard"></a><font color=Blue>-- | @x `discard` y@ parses both x and y, but discards the result of y.</font>
<a name="line-97"></a><font color=Blue>-- Rather like @const@ lifted into parsers.</font>
<a name="line-98"></a><font color=Blue>discard</font> <font color=Red>::</font> PolyParse p <font color=Red>=></font> p a <font color=Red>-></font> p b <font color=Red>-></font> p a
<a name="line-99"></a><a name="discard"></a><font color=Blue>px</font> <font color=Cyan>`discard`</font> py <font color=Red>=</font> <font color=Green><u>do</u></font> <font color=Cyan>{</font> x <font color=Red><-</font> px<font color=Cyan>;</font> py<font color=Cyan>;</font> return x<font color=Cyan>;</font> <font color=Cyan>}</font>
<a name="line-100"></a>
<a name="line-101"></a><a name="adjustErrBad"></a><font color=Blue>-- | @adjustErrBad@ is just like @adjustErr@ except it also raises the</font>
<a name="line-102"></a><font color=Blue>-- severity of the error.</font>
<a name="line-103"></a><font color=Blue>adjustErrBad</font> <font color=Red>::</font> PolyParse p <font color=Red>=></font> p a <font color=Red>-></font> <font color=Cyan>(</font>String<font color=Red>-></font>String<font color=Cyan>)</font> <font color=Red>-></font> p a
<a name="line-104"></a><a name="adjustErrBad"></a><font color=Blue>p</font> <font color=Cyan>`adjustErrBad`</font> f <font color=Red>=</font> commit <font color=Cyan>(</font>p <font color=Cyan>`adjustErr`</font> f<font color=Cyan>)</font>
<a name="line-105"></a>
<a name="line-106"></a><a name="oneOf"></a><font color=Blue>-- | Parse the first alternative in the list that succeeds.</font>
<a name="line-107"></a><font color=Blue>oneOf</font> <font color=Red>::</font> PolyParse p <font color=Red>=></font> <font color=Red>[</font>p a<font color=Red>]</font> <font color=Red>-></font> p a
<a name="line-108"></a><font color=Blue>oneOf</font> [] <font color=Red>=</font> fail <font color=Cyan>(</font><font color=Magenta>"failed to parse any of the possible choices"</font><font color=Cyan>)</font>
<a name="line-109"></a><font color=Blue>oneOf</font> <font color=Cyan>(</font>p<font color=Red><b>:</b></font>ps<font color=Cyan>)</font> <font color=Red>=</font> p <font color=Cyan>`onFail`</font> oneOf ps
<a name="line-110"></a><font color=Blue>--oneOf :: Show t => [Parser t a] -> Parser t a</font>
<a name="line-111"></a><font color=Blue>--oneOf [] = do { n <- next</font>
<a name="line-112"></a><font color=Blue>-- ; fail ("failed to parse any of the possible choices"</font>
<a name="line-113"></a><font color=Blue>-- ++"\n next token is "++show n)</font>
<a name="line-114"></a><font color=Blue>-- }</font>
<a name="line-115"></a><font color=Blue>--oneOf (p:ps) = p `onFail` oneOf ps</font>
<a name="line-116"></a>
<a name="line-117"></a><a name="indent"></a><font color=Blue>-- | Helper for formatting error messages: indents all lines by a fixed amount.</font>
<a name="line-118"></a><font color=Blue>indent</font> <font color=Red>::</font> Int <font color=Red>-></font> String <font color=Red>-></font> String
<a name="line-119"></a><font color=Blue>indent</font> n <font color=Red>=</font> unlines <font color=Cyan>.</font> map <font color=Cyan>(</font>replicate n <font color=Magenta>' '</font> <font color=Cyan>++</font><font color=Cyan>)</font> <font color=Cyan>.</font> lines
<a name="line-120"></a>
<a name="line-121"></a><a name="optional"></a><font color=Blue>-- | 'optional' indicates whether the parser succeeded through the Maybe type.</font>
<a name="line-122"></a><font color=Blue>optional</font> <font color=Red>::</font> PolyParse p <font color=Red>=></font> p a <font color=Red>-></font> p <font color=Cyan>(</font>Maybe a<font color=Cyan>)</font>
<a name="line-123"></a><font color=Blue>optional</font> p <font color=Red>=</font> fmap Just p <font color=Cyan>`onFail`</font> return Nothing
<a name="line-124"></a>
<a name="line-125"></a><a name="exactly"></a><font color=Blue>-- | 'exactly n p' parses precisely n items, using the parser p, in sequence.</font>
<a name="line-126"></a><font color=Blue>exactly</font> <font color=Red>::</font> PolyParse p <font color=Red>=></font> Int <font color=Red>-></font> p a <font color=Red>-></font> p <font color=Red>[</font>a<font color=Red>]</font>
<a name="line-127"></a><font color=Blue>exactly</font> <font color=Magenta>0</font> p <font color=Red>=</font> return []
<a name="line-128"></a><font color=Blue>exactly</font> n p <font color=Red>=</font> return <font color=Cyan>(</font><font color=Red><b>:</b></font><font color=Cyan>)</font> <font color=Cyan>`apply`</font> <font color=Cyan>(</font>p <font color=Cyan>`adjustErr`</font> <font color=Cyan>(</font><font color=Cyan>(</font><font color=Magenta>"When expecting exactly "</font>
<a name="line-129"></a> <font color=Cyan>++</font>show n<font color=Cyan>++</font><font color=Magenta>" more items"</font><font color=Cyan>)</font><font color=Cyan>++</font><font color=Cyan>)</font><font color=Cyan>)</font>
<a name="line-130"></a> <font color=Cyan>`apply`</font> exactly <font color=Cyan>(</font>n<font color=Blue>-</font><font color=Magenta>1</font><font color=Cyan>)</font> p
<a name="line-131"></a>
<a name="line-132"></a><a name="many"></a><font color=Blue>-- | 'many p' parses a list of elements with individual parser p.</font>
<a name="line-133"></a><font color=Blue>-- Cannot fail, since an empty list is a valid return value.</font>
<a name="line-134"></a><font color=Blue>many</font> <font color=Red>::</font> PolyParse p <font color=Red>=></font> p a <font color=Red>-></font> p <font color=Red>[</font>a<font color=Red>]</font>
<a name="line-135"></a><font color=Blue>many</font> p <font color=Red>=</font> many1 p <font color=Cyan>`onFail`</font> return []
<a name="line-136"></a>
<a name="line-137"></a><a name="many1"></a><font color=Blue>-- | Parse a non-empty list of items.</font>
<a name="line-138"></a><font color=Blue>many1</font> <font color=Red>::</font> PolyParse p <font color=Red>=></font> p a <font color=Red>-></font> p <font color=Red>[</font>a<font color=Red>]</font>
<a name="line-139"></a><font color=Blue>many1</font> p <font color=Red>=</font> <font color=Green><u>do</u></font> <font color=Cyan>{</font> x <font color=Red><-</font> p <font color=Cyan>`adjustErr`</font> <font color=Cyan>(</font><font color=Cyan>(</font><font color=Magenta>"In a sequence:\n"</font><font color=Cyan>++</font><font color=Cyan>)</font><font color=Cyan>.</font> indent <font color=Magenta>2</font><font color=Cyan>)</font>
<a name="line-140"></a> <font color=Cyan>;</font> return <font color=Cyan>(</font>x<font color=Red><b>:</b></font><font color=Cyan>)</font> <font color=Cyan>`apply`</font> many p
<a name="line-141"></a> <font color=Cyan>}</font>
<a name="line-142"></a><font color=Blue>-- `adjustErr` ("When looking for a non-empty sequence:\n\t"++)</font>
<a name="line-143"></a>
<a name="line-144"></a><a name="sepBy"></a><font color=Blue>-- | Parse a list of items separated by discarded junk.</font>
<a name="line-145"></a><font color=Blue>sepBy</font> <font color=Red>::</font> PolyParse p <font color=Red>=></font> p a <font color=Red>-></font> p sep <font color=Red>-></font> p <font color=Red>[</font>a<font color=Red>]</font>
<a name="line-146"></a><font color=Blue>sepBy</font> p sep <font color=Red>=</font> <font color=Green><u>do</u></font> sepBy1 p sep <font color=Cyan>`onFail`</font> return []
<a name="line-147"></a>
<a name="line-148"></a><a name="sepBy1"></a><font color=Blue>-- | Parse a non-empty list of items separated by discarded junk.</font>
<a name="line-149"></a><font color=Blue>sepBy1</font> <font color=Red>::</font> PolyParse p <font color=Red>=></font> p a <font color=Red>-></font> p sep <font color=Red>-></font> p <font color=Red>[</font>a<font color=Red>]</font>
<a name="line-150"></a><font color=Blue>sepBy1</font> p sep <font color=Red>=</font> <font color=Green><u>do</u></font> <font color=Cyan>{</font> x <font color=Red><-</font> p
<a name="line-151"></a> <font color=Cyan>;</font> return <font color=Cyan>(</font>x<font color=Red><b>:</b></font><font color=Cyan>)</font> <font color=Cyan>`apply`</font> many <font color=Cyan>(</font><font color=Green><u>do</u></font> <font color=Cyan>{</font>sep<font color=Cyan>;</font> p<font color=Cyan>}</font><font color=Cyan>)</font>
<a name="line-152"></a> <font color=Cyan>}</font>
<a name="line-153"></a> <font color=Cyan>`adjustErr`</font> <font color=Cyan>(</font><font color=Magenta>"When looking for a non-empty sequence with separators:\n\t"</font><font color=Cyan>++</font><font color=Cyan>)</font>
<a name="line-154"></a>
<a name="line-155"></a><a name="bracketSep"></a><font color=Blue>-- | Parse a list of items, discarding the start, end, and separator</font>
<a name="line-156"></a><font color=Blue>-- items.</font>
<a name="line-157"></a><font color=Blue>bracketSep</font> <font color=Red>::</font> PolyParse p <font color=Red>=></font> p bra <font color=Red>-></font> p sep <font color=Red>-></font> p ket <font color=Red>-></font> p a <font color=Red>-></font> p <font color=Red>[</font>a<font color=Red>]</font>
<a name="line-158"></a><font color=Blue>bracketSep</font> open sep close p <font color=Red>=</font>
<a name="line-159"></a> <font color=Green><u>do</u></font> <font color=Cyan>{</font> open<font color=Cyan>;</font> close<font color=Cyan>;</font> return [] <font color=Cyan>}</font>
<a name="line-160"></a> <font color=Cyan>`onFail`</font>
<a name="line-161"></a> <font color=Green><u>do</u></font> <font color=Cyan>{</font> open <font color=Cyan>`adjustErr`</font> <font color=Cyan>(</font><font color=Magenta>"Missing opening bracket:\n\t"</font><font color=Cyan>++</font><font color=Cyan>)</font>
<a name="line-162"></a> <font color=Cyan>;</font> x <font color=Red><-</font> p <font color=Cyan>`adjustErr`</font> <font color=Cyan>(</font><font color=Magenta>"After first bracket in a group:\n\t"</font><font color=Cyan>++</font><font color=Cyan>)</font>
<a name="line-163"></a> <font color=Cyan>;</font> return <font color=Cyan>(</font>x<font color=Red><b>:</b></font><font color=Cyan>)</font>
<a name="line-164"></a> <font color=Cyan>`apply`</font> manyFinally <font color=Cyan>(</font><font color=Green><u>do</u></font> <font color=Cyan>{</font>sep<font color=Cyan>;</font> p<font color=Cyan>}</font><font color=Cyan>)</font>
<a name="line-165"></a> <font color=Cyan>(</font>close <font color=Cyan>`adjustErrBad`</font> <font color=Cyan>(</font><font color=Magenta>"When looking for closing bracket:\n\t"</font><font color=Cyan>++</font><font color=Cyan>)</font><font color=Cyan>)</font>
<a name="line-166"></a> <font color=Cyan>}</font>
<a name="line-167"></a>
<a name="line-168"></a><a name="bracket"></a><font color=Blue>-- | Parse a bracketed item, discarding the brackets.</font>
<a name="line-169"></a><font color=Blue>bracket</font> <font color=Red>::</font> PolyParse p <font color=Red>=></font> p bra <font color=Red>-></font> p ket <font color=Red>-></font> p a <font color=Red>-></font> p a
<a name="line-170"></a><font color=Blue>bracket</font> open close p <font color=Red>=</font> <font color=Green><u>do</u></font>
<a name="line-171"></a> <font color=Green><u>do</u></font> <font color=Cyan>{</font> open <font color=Cyan>`adjustErr`</font> <font color=Cyan>(</font><font color=Magenta>"Missing opening bracket:\n\t"</font><font color=Cyan>++</font><font color=Cyan>)</font>
<a name="line-172"></a> <font color=Cyan>;</font> p <font color=Cyan>`discard`</font> <font color=Cyan>(</font>close <font color=Cyan>`adjustErrBad`</font> <font color=Cyan>(</font><font color=Magenta>"Missing closing bracket:\n\t"</font><font color=Cyan>++</font><font color=Cyan>)</font><font color=Cyan>)</font>
<a name="line-173"></a> <font color=Cyan>}</font>
<a name="line-174"></a>
<a name="line-175"></a><a name="manyFinally"></a><font color=Blue>-- | 'manyFinally e t' parses a possibly-empty sequence of e's,</font>
<a name="line-176"></a><font color=Blue>-- terminated by a t. The final t is discarded. Any parse failures</font>
<a name="line-177"></a><font color=Blue>-- could be due either to a badly-formed terminator or a badly-formed</font>
<a name="line-178"></a><font color=Blue>-- element, so it raises both possible errors.</font>
<a name="line-179"></a><font color=Blue>manyFinally</font> <font color=Red>::</font> PolyParse p <font color=Red>=></font> p a <font color=Red>-></font> p z <font color=Red>-></font> p <font color=Red>[</font>a<font color=Red>]</font>
<a name="line-180"></a><font color=Blue>manyFinally</font> p t <font color=Red>=</font>
<a name="line-181"></a> <font color=Cyan>(</font>many p <font color=Cyan>`discard`</font> t<font color=Cyan>)</font>
<a name="line-182"></a> <font color=Cyan>`onFail`</font>
<a name="line-183"></a> oneOf' <font color=Red>[</font> <font color=Cyan>(</font><font color=Magenta>"sequence terminator"</font><font color=Cyan>,</font> <font color=Green><u>do</u></font> <font color=Cyan>{</font> t<font color=Cyan>;</font> return [] <font color=Cyan>}</font> <font color=Cyan>)</font>
<a name="line-184"></a> <font color=Cyan>,</font> <font color=Cyan>(</font><font color=Magenta>"item in a sequence"</font><font color=Cyan>,</font> <font color=Green><u>do</u></font> <font color=Cyan>{</font> p<font color=Cyan>;</font> return [] <font color=Cyan>}</font> <font color=Cyan>)</font>
<a name="line-185"></a> <font color=Red>]</font>
<a name="line-186"></a><font color=Blue>{-
<a name="line-187"></a>manyFinally p t =
<a name="line-188"></a> do { xs <- many p
<a name="line-189"></a> ; oneOf' [ ("sequence terminator", do { t; return () } )
<a name="line-190"></a> , ("item in a sequence", do { p; return () } )
<a name="line-191"></a> ]
<a name="line-192"></a> ; return xs
<a name="line-193"></a> }
<a name="line-194"></a>-}</font>
<a name="line-195"></a><font color=Blue>------------------------------------------------------------------------</font>
</pre>
</html>