There are different degrees of laziness.
One might say that your function is strict since partitions undefined
triggers an exception, but that would be too pedantic.
Chances are that by "lazy" you actually mean "it will produce a part the output after having accessed only a part of the input". Several degrees of laziness then arise, depending on how much input is needed for each part of the output.
In your case, the shape of the function is as follows:
foo [] = (some constant value)
foo (x:xs) = C expression1 ... expressionN
where C
is a value constructor. More precisely, C = (:)
and N=2
. Since Haskell constructors are lazy (unless bang annotations are involved), the result of foo (x:xs)
will always be non-bottom: consuming an element in the input list is enough to produce an element of the output list.
You might be confused by the output of partitions [1..]
being an infinite list of pairs (xs, ys)
where each ys
is an infinite list. This makes the notion of laziness much more complex, since you might now wonder, e.g., "how much input is accessed for me to take the 100th pair of the output, and then access the 500th element of its second component?". Such questions are perfectly legitimate, and tricky to answer in general.
Still, your code will never demand the full input list to output a finite portion of the output. This makes it "lazy".
For completeness, let me show a non lazy function:
partitions (x:xs) = case partitions xs of
[] -> expression0
(y:ys) -> expression1 : expression2
Above, the result of the recursive call is demanded before the head of the output list is produced. That will demand the whole input before any part of the output is generated.