I have a somewhat techinical question about the inner workings of (Mega)Parsec, the informal context of which is:
What is the idea governing the accumulation/propagation of error messages through continuations in
Parsec
?
Specifically:
Consider the mplus
operation making ParsecT
an instance of MonadPlus
.
(source)
mplus m n
takes, as input, a string s
to parse and continuations cok
, cerr
, eok
, and eerr
to follow based on the result of the parse.
First parse s
with m
:
- If the parse succeeds and consumes (respectively, does not consume) part of
s
, follow thecok
(respectively,eok
) continuation. - If the parse of
s
withm
fails while consuming part ofs
, follow thecerr
continuation. - Suppose the parse of
s
withm
fails without consuming anything; leterr
be the parse error associated with this failure. We then try parsings
withn
, and choose a continuation accordingly:- If the parse of
s
withn
succeeds while consuming input, follow thecok
continuation. - If the parse of
s
withn
fails while consuming input, follow thecerr
continuation. - If the parse of
s
withn
succeeds without consuming input, follow a continuationneok
derived fromeok
:neok y s' err' = eok y s' (mergeError err err')
- If the parse of
s
withn
fails without consuming input, follow a continuationneerr
derived fromeerr
:neerr y s' err' = eerr (mergeError err err')
- If the parse of
My question is:
Why do we merge errors when following an 'empty' continuation and not when following a 'consumed' continuation, thereby forgetting about all previous errors?
This must be a design decision, but I can't figure out the reasoning behind it. Is there, perhaps, a simple example that would clarify this?