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

Russ Lewis spamhole-2001-07-16 at deming-os.org
Tue Apr 6 23:41:27 EDT 2004


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
>



More information about the Haskell-Cafe mailing list