I am trying to understand the lazy evaluation of Haskell and made the following attempt in GHCi
GHCi, version 8.0.2: http://www.haskell.org/ghc/ :? for help
Prelude> :set +m
Prelude> let iterateUntilError1 :: (a->a) -> (a->a)
Prelude| iterateUntilError1 f = (iterateUntilError1 f) . f
Prelude|
Prelude> let iterateUntilError2 :: (a->a) -> (a->a)
Prelude| iterateUntilError2 f = \x -> (iterateUntilError2 f) . f $ x
Prelude|
Prelude> let iterateUntilError3 :: (a->a) -> (a->a)
Prelude| iterateUntilError3 f = \x -> (iterateUntilError3 f) . f $! x
Prelude|
Prelude> let iterateUntilError4 x = foldl1 (.) (repeat (($!) x))
Prelude> iterateUntilError3 tail [1..5]
*** Exception: Prelude.tail: empty list
Prelude> iterate tail [1..5]
[[1,2,3,4,5],[2,3,4,5],[3,4,5],[4,5],[5],[],*** Exception: Prelude.tail: empty list
Among the 4 versions presented, only iterateUntilError3
works as expected, the other 3 versions enter an infinite loop that has to be stopped via Ctrl+C. I don't quite understand why the other three versions don't work in this case.
The related question laziness and function composition (haskell, erlang) does not seem to address the issues presented in this question.