[Haskell-cafe] Newbie: Is it possible to catch _|_ ?

Graham Klyne GK at ninebynine.org
Wed Apr 7 11:51:30 EDT 2004


I'm not familiar with yacc, but I understand that it's a bottom-up parser 
generator.  I've not come across any bottom-up parser generators written in 
Haskell.

I have seen (at least) three examples of top-down parser generators coded 
in Haskell:
(1) in Simon Thompson's book, the Craft of Functional Programming.  I have 
done an implementation based on these ideas [3], which I have since 
discarded in favour of Parsec...
(2) the Parsec parser library [1], which is a very full-functioned and 
easy-to-use library, but which might be not-so-easy for a Haskell newcomer 
to figure out its internal workings because it is heavily based on Monads.
(3) the HuttonMeijerWallace parser combinator library [2], which is also 
based on a Monad but, being less complex, is easier to follow its internals.

[1] http://www.cs.uu.nl/~daan/parsec.html
     (also in the Haskell hierarchical libraries, under 'text'.

[2] API Documentation:
http://www.cs.york.ac.uk/fp/HaXml/HaXml/Text.ParserCombinators.HuttonMeijerWallace.html
Source in CVS:
http://cvs.haskell.org/cgi-bin/cvsweb.cgi/HaXml/src/Text/ParserCombinators/HuttonMeijerWallace.hs
Being part of HaXml:
http://www.cs.york.ac.uk/fp/HaXml/

[3] http://www.ninebynine.org/Software/HaskellUtils/Withdrawn/Parse.hs
(And related code in same directory.  This was just about the first real 
program I write in Haskell, so don't look to this for an example of how one 
*should* program using Haskell!)

#g
--

At 22:41 06/04/04 -0700, Russ Lewis wrote:
>I am new to Haskell (and to functional programming).  In fact, I haven't 
>written a single line of Haskell code.  But I love programming languages, 
>and when I read the Gentle Introduction to Haskell, I started pondering 
>how to use Haskell to solve my current favorite problem, which is the 
>generation of parsers for yacc-style languages.
>
>I asked this question on the list because, in my trivial implementation of 
>a Haskell yacc parser, there is the potential for expressions which expand 
>to themselves.  I don't know how I would avoid this without making the 
>yacc->Haskell translation substantially nontrivial.
>
>Basically, you figure that for each yacc symbol, you define a function 
>which takes as input a list of tokens and returns a list of list of 
>tokens; in each list, the first token is what you were parsing for and the 
>rest is any remaining tokens in the stream.  So the yacc symbol:
>
>exp2:
>   NUM
>;
>
>would turn into Haskell code something like this:
>
>parse_exp1 [] = []
>parse_exp1 token NUM:xs = (token exp1 NUM:xs):[]
>parse_exp1 xs = []
>
>The last line simply says that if there are no matches, then there are no 
>parsings available.
>
>More complex symbols like
>   exp2:
>      exp1 "++"
>   ;
>
>Would require recursion like this:
>
>   parse_exp2 [] = []
>   parse_exp2 token exp1 a : token '++' : xs = (token exp2 exp1 a : xs) : []
>   parse_exp2 xs = join_lists map parse_exp2 parse_exp1 xs
>
>.....where join_lists joins all of the returned lists of lists into a 
>single list of lists
>
>Finally, expressions with multiple possible parsings, such as
>   exp3:
>      NUM
>      exp4
>   ;
>
>would require multiple parse stacks returned:
>   parse_exp3 [] = []
>   parse_exp3 token NUM : xs = ((token exp3 NUM) : xs) : ( parse_exp3 
> parse_exp4 token NUM : xs )
>   ... (more expressions) ...
>
>The complex 2nd line is required because the parser needs to consider the 
>fact that the correct parsing might be to parse NUM->exp3 OR the correct 
>parsing might be NUM.....->exp4->exp3.  So it generates a pair of parse 
>stacks, one for each possibility.
>
>But what if exp4 recurses back into exp3 with this yacc definition?
>   exp4:
>      exp3 "++"
>   ;
>
>Now the expression 'parse_exp3 parse_exp4 ......' is going to expand to 
>include 'parse_exp3' of the same token stream.  This is obviously an 
>infinite loop.
>
>What I was hoping was that Haskell would detect the infinte loop, and I 
>could basically "catch" that infinite loop and turn it into [] (i.e. no 
>valid parsing down this path).
>
>Now I have to find something else, I guess...
>
>Russ Lewis
>
>Iavor S. Diatchki wrote:
>
>>hello,
>>this is an attempt to give an answer to someone who is new to Haskell.
>>
>>the answer to your question is: no, there is no way to "catch" _|_,
>>as that would mean that we can solve the halting problem.
>>a piece of advice, especially while you are new to haskell ---
>>don't worry too much about _|_. occasonally you will run into
>>an infinite loop, but that probably means you have a bug in your program,
>>so fix it, and don't try to "catch" it.
>>
>>as an unrelated comment, Haskell does have some exception handling features,
>>but they often get pretty advanced.  mostly these are unrelated to _|_.
>>
>>what the previous answers were saying, is that some implementations 
>>(notably GHC)
>>can sometimes detect that a program will loop forever, and instead of 
>>generating
>>code that will simply loop, they generate code that produces a helpful 
>>message,
>>so that you can fix your program.
>>
>>the way this particular feture happens to be implemented in GHC is that
>>it generates code that raises an exception.  it is hard to see why one 
>>might want
>>to handle this exception, especially since there are no guarantees 
>>whatsoever that
>>it will ever occur.  furthermore this is highly GHC specific behaviour.
>>
>>hope this is helpful
>>-iavor
>>
>>
>>
>>Jon Cast wrote:
>>
>>>Russ Lewis <spamhole-2001-07-16 at deming-os.org> wrote:
>>>
>>>
>>>
>>>>Another newbie question: Is it possible to catch _|_ - that is, to 
>>>>encounter it, handle it and continue?  I'm assuming that you all are 
>>>>going to say no, since I can't figure out any way to do this and retain 
>>>>the functional nature of Haskell.
>>>>
>>>
>>>
>>>This isn't possible in a deterministic language, for several reasons.
>>>The IO monad, however, is non-deterministic, and its `catch' function
>>>can be used to catch any _|_ value that can be caught, specifically
>>>those arising from calls to throw, error, and certain infinite loops.
>>>It is non-deterministic, though, so it won't catch all _|_s, nor will it
>>>give any guarantee as to which _|_ it will catch (for example, in error
>>>3 + throw (DynException (toDynamic False)) it's indeterminate whether
>>>error's return value or throw's return value will ultimately be caught.
>>>
>>>Jon Cast
>>>_______________________________________________
>>>Haskell-Cafe mailing list
>>>Haskell-Cafe at haskell.org
>>>http://www.haskell.org/mailman/listinfo/haskell-cafe
>
>_______________________________________________
>Haskell-Cafe mailing list
>Haskell-Cafe at haskell.org
>http://www.haskell.org/mailman/listinfo/haskell-cafe

------------
Graham Klyne
For email:
http://www.ninebynine.org/#Contact



More information about the Haskell-Cafe mailing list