Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do stack overflow errors occur in Haskell?

As a pure functional programming language, Haskell intensively uses recursion. Do stack overflow errors occur in Haskell, like in Java? Why, or why not?

like image 990
Chenyu Avatar asked Apr 06 '17 20:04

Chenyu


People also ask

Does Haskell have a stack?

Stack is a tool to build Haskell projects and manage their dependencies. It uses the Cabal library but with a curated version of the Hackage repository called Stackage.

What causes stack overflow errors?

The most-common cause of stack overflow is excessively deep or infinite recursion, in which a function calls itself so many times that the space needed to store the variables and information associated with each call is more than can fit on the stack.

What type of error is stack overflow?

What is stack overflow? A stack overflow is a type of buffer overflow error that occurs when a computer program tries to use more memory space in the call stack than has been allocated to that stack.

What is the condition to check for stack overflow?

Overflow condition: When stack is completely full (i.e. TOP= MaxSize -1 ) and we try to insert more element onto stack then this condition is called overflow condition and no further element could be inserted now until any element is deleted.


1 Answers

Haskell uses the stack differently from Java, due to laziness.

In Java, a stack frame is created when a method is called, and freed when the method returns. So if f() is a recursive method, each recursive call to f() generates a stack frame, and these frames are strictly nested. You can get a stack overflow when you have a deep chain of recursive calls, like f() -> f() -> f() -> ….

Whereas in Haskell, a thunk is created when a function is called. A stack frame is created when a thunk is forced using pattern-matching (e.g. case), and freed when evaluation of the thunk is complete enough to return a value (which may contain more unevaluated thunks).

So if f is a recursive function, each call to f generates a thunk, and case on the result of this generates a stack frame, but these frames are only nested when there’s a dependency between thunks. And in fact, that’s what the seq primitive does: a `seq` b means “evaluate a before b, returning b”, but you can also think of it as adding a dependency of b on a, so when b is evaluated, a is also forced.

You can get a stack overflow when you have a deep chain of thunks to evaluate, for example in the excessively lazy foldl function:

foldl (+) 0 [1..5]
==
foldl (+) 0 (1 : 2 : 3 : 4 : 5 : [])
==
((((0 + 1) + 2) + 3) + 4) + 5

This generates a chain of thunks like so:

((+)
    ((+)
        ((+)
            ((+)
                ((+)
                    0
                    1)
                2)
            3)
        4)
    5)

When we force the result (for example, by printing it) we need to descend all the way down this chain in order to be able to start evaluating it, at the (+) 0 1 thunk.

So foldl often produces stack overflows for large inputs, which is why most of the time you should use foldl' (which is strict) when you want a left-associative fold. Instead of building a chain of nested thunks, foldl' evaluates the intermediate results immediately (0+1 = 1, 1+2 = 3, 3+3 = 6, …).

like image 154
Jon Purdy Avatar answered Sep 18 '22 23:09

Jon Purdy