I'm confused by Haskell's lazy evaluation

haskell, lazy-evaluation

Solution

This is more of a question about particular Haskell implementations than about Haskell itself, since the language makes no particular guarantees about how things are evaluated.

But in GHC (and most other implementations, as far as I'm aware): yes, when thunks are evaluated they are replaced by the result internally, so other references to the same thunk benefit from the work done evaluating it the first time.

The caveat is that there are no real guarantees about which expressions end up implemented as references to the same thunk. The compiler is in general allowed to make whatever transformations to your code it likes so long as the result is the same. Of course, the reason to implement code transformations in a compiler is usually to try to make the code faster, so it's hopefully not likely to rewrite things in such a way as to make it worse, but it can never be perfect.

In practice though, you're usually pretty safe assuming that whenever you give an expression a name (as in `where x = head [1..]`), then all uses of that name (within the scope of the binding) will be references to a single thunk.

Problem

I'm concerned about efficiency in Haskell's lazy evaluation. consider following code ``` main = print $ x + x where x = head [1..] ``` here, `x` first hold the expression of `head [1..]` instead of the result `1`, due to the laziness, but then when I call `x + x`, will the expression `head [1..]` be executed twice? I found the following description on haskell.org Lazy evaluation, on the other hand, means only evaluating an expression when its results are needed (note the shift from "reduction" to "evaluation"). So when the evaluation engine sees an expression it builds a thunk data structure containing whatever values are needed to evaluate the expression, plus a pointer to the expression itself. When the result is actually needed the evaluation engine calls the expression and then replaces the thunk with the result for future reference. So does this mean that, in `x + x`, when calling the first `x`, `head [1..]` is executed and `x` is re-assigned to `1`, and the second `x` is just calling a reference of it? Did I understand this right?

Original source