Re: [Haskell-cafe] Re: [Haskell] Parsec question: attempted 'notMatching' combinator

2004-02-18 Thread Andrew Pimlott
On Wed, Feb 18, 2004 at 10:48:39AM +, Graham Klyne wrote:
> [To Haskell-cafe...]
> 
> At 16:57 17/02/04 -0500, Andrew Pimlott wrote:
> >On Tue, Feb 17, 2004 at 07:48:52PM +, Graham Klyne wrote:
> >> [[
> >> notMatching :: Show a => GenParser tok st a -> GenParser tok st ()
> >> notMatching p = do { a <- try p ; unexpected (show a) } <|> return ()
> >> ]]
> >
> >notFollowedBy' :: Show a => GenParser tok st a -> GenParser tok st ()
> >notFollowedBy' p= do  res <-  do a <- try p; return $ Just a
> >  <|>
> >  return Nothing
> >  case res of Just a  -> unexpected (show a)
> >  Nothing -> return ()
> 
> I don't see why that would work where the above case does not;  i.e. when p 
> consumes no input.

Because (in my version) when p succeeds, the left side of <|> succeeds;
in the original, the left side of <|> always failed.  Instead of
throwing the error immediately after p succeeds, I "package it up" in
Just a and throw it later.  So there is no possibility for the right
side of <|> to be evaluated "by accident", as there was in the original.

I think the key is to understand the paragraph in a previous message
about the original implementation being a "dirty trick".

Andrew
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Re: [Haskell] Parsec question: attempted 'notMatching' combinator

2004-02-18 Thread Graham Klyne
[To Haskell-cafe...]

At 16:57 17/02/04 -0500, Andrew Pimlott wrote:
On Tue, Feb 17, 2004 at 07:48:52PM +, Graham Klyne wrote:
> Thanks!  That got me going, though not with quite what you suggested.
>
> I ended up with this:
> [[
> notMatching :: Show a => GenParser tok st a -> GenParser tok st ()
> notMatching p = do { a <- try p ; unexpected (show a) } <|> return ()
> ]]
> which does the required job for me.
Oops, that does look better.  I knew the try had to go somewhere.  :-)

The only remaining problem is when p succeeds but does not consume any
input, eg eof.  In this case, the <|> return () cannot distinguish it
from p failing.
I didn't realize at first what a dirty trick this function uses:  It
distinguishes success or failure of p by whether any input from the
first part (before <|> return ()) was consumed.  I don't think it is
possible (or desirable!) to get this approach 100% right:  By "erasing"
the success of p, you lose the information you need.
What about a more prosaic implementation:

notFollowedBy' :: Show a => GenParser tok st a -> GenParser tok st ()
notFollowedBy' p= do  res <-  do a <- try p; return $ Just a
  <|>
  return Nothing
  case res of Just a  -> unexpected (show a)
  Nothing -> return ()
I don't see why that would work where the above case does not;  i.e. when p 
consumes no input.

Or indeed, your later, preferred version:
[[
notFollowedBy' :: Show a => GenParser tok st a -> GenParser tok st ()
notFollowedBy' p= join $  do a <- try p; return (unexpected (show a))
  <|>
  return (return ())
]]

This works for the tests I've tried, but there's one little quirk with
error reporting:
I never really cared so much about that bit!

#g
--
aNoBC = do  char 'a'
notFollowedBy' $ do  char 'b'; char 'c'
*Main> parseTest (aNoBC >> char 'e') "abe"
parse error at (line 1, column 2):
unexpected "e"
expecting "c" or "e"
It seems that parsec both misreports which token is unexpected (should
be "b", and thinks that the failure to match "c" is a problem, even
though notFollowedBy' succeeded.
> Using your version caused the notMatching parser to be equivalent to:
>   return ()
> presumably, because the failure was protected by the try combinator?
Or perhaps more accurately, the success (of p) was protected by the try!
Ie, the unexpected and the try together undid the tell-tale token
consumption of p.
Andrew

Graham Klyne
For email:
http://www.ninebynine.org/#Contact
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe