The way to think about a `seq` b
is not that it "evaluates a
" but that it creates a dependency between a
and b
, so that when you go to evaluate b
you evaluate a
as well.
This means, for example, that a `seq` a
is completely redundant: you're telling Haskell to evaluate a
when you evaluate a
. By the same logic, seq a
with just one argument would not be any different than simply writing a
by itself.
Just having seq a
that somehow evaluates a
would not work. The problem is that seq a
is itself an expression that might not be evaluated—it might be deep inside some nested thunks, for example. So it would only become relevant when you get to evaluating the whole seq a
expression—at which point you would have been evaluating a
by itself anyhow.
@Rhymoid's example of how it's used in a strict fold (foldl'
) is good. Our goal is to write a fold such that its intermediate accumulated value (acc
) is completely evaluated at each step as soon as we evaluate the final result. This is done by adding a seq
between the accumulated value and the recursive call:
foldl' f z (x:xs) =
let z' = f z x in z' `seq` foldl' f z' xs
You can visualize this as a long chain of seq
between each application of f
in the fold, connecting all of them to the final result. This way when you evaluate the final expression (ie the number you get by by summing a list), it evaluates the intermediate values (ie partial sums as you fold through the list) strictly.
foldl'
, you see that you often just want to strictly evaluate some let-bound variable ina
that you feed into yourb
value. – Smokechaser