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.