If so, is this a part of the standard or a ghc specific optimisation we can depend on? Or just an optimisation which we can’t necessarily depend on.
P.S.:
When I tried a test sample, it seemed to indicate that it was taking place/
Prelude> let isOdd x = x `mod` 2 == 1
Prelude> let isEven x = x `mod` 2 == 0
Prelude> ((filter isOdd).(filter isEven)) [1..]
Chews up CPU but doesn’t consume much memory.
Depends on what you mean by generator. The list is lazily generated, and since nothing else references it, the consumed parts are garbage collected almost immediately. Since the result of the above computation doesn’t grow, the entire computation runs in constant space. That is not mandated by the standard, but as it is harder to implement nonstrict semantics with different space behaviour for that example (and lots of vaguely similar), in practice you can rely on it.
But normally, the list is still generated as a list, so there’s a lot of garbage produced. Under favourable circumstances, ghc eliminates the list
[1 .. ]and produces a non-allocating loop:(using the Prelude functions out of laziness), compiled with
-O2generates the coreA plain loop, running from 1 to
maxBound :: Int, producing nothing on the way and[]at the end.It’s almost smart enough to plain return
[]. Note that there’s only one division by 2, GHC knows that if anIntis even, it can’t be odd, so that check has been eliminated, and in no branch a non-empty list is created (i.e., the unreachable branches have been eliminated by the compiler).