3 ms·
Although you eliminate null pointer exceptions, lazy evaluation does introduce another subtle and very similar class of errors. Consider a program that takes a
by Chirono 16y ago
Although you eliminate null pointer exceptions, lazy evaluation does introduce another subtle and very similar class of errors.
Consider a program that takes a leaf-labelled tree of Ints and replaces each int with the maximum found in the whole tree. You can do this in two passes over the tree - one to find the max value, one to re-write the tree.
But you can also do it in a single pass using lazy evaluation:
----------------
data Tree = Branch Tree Tree | Leaf Int
label :: Tree -> Tree
label tree = t2
where (t2,k) = thread tree k
thread :: Tree -> Int -> (Tree,Int)
thread (Leaf v) k = (Leaf k, v)
thread (Branch l r) k = (Branch l' r', max lv rv)
where
(l',lv) = thread l k
(r',rv) = thread r k
----------------
The idea here is that `thread` runs through the tree replacing the values with some input value `k` and also calculates the max value of the tree. The function `label` then uses the output of thread as its own input.
This all works fine as long as you never look at the value of `k` inside `thread`. If you do, you go into an infinite loop as `k` then depends on itself.
This is similar to `k` being a pointer to an Int that doesn't get initialised until the function `thread` returns. If you examine it before then, you get a null pointer exception.
- masklinn 16y ago> Although you eliminate null pointer exceptions, lazy evaluation does introduce another subtle and very similar class of errors. But those are completely different features, option types don't imply lazy evaluation (and the other way around). OP didn't talk about lazy evaluation once. There might be issues with lazy eval, but that's completely not the subject.
- deleted 16y ago[deleted]
- Chirono 16y agoYeah, I know they aren't related. I just thought it might be interesting to show that this kind of bug can still crop up even without nullable types. So the statement made at the end of the post doesn't quite hold: > In Haskell, it is simply impossible to write a program that is susceptible to NullPointerExceptions at runtime unless you explicitly make the type in question optional by wrapping with Maybe. That said, lazy knot-tying isn't something you tend to write by accident. You generally know that it's going on.