For the sake of this question, let's say that there are three things that can force a value to actually be evaluated:
- Pattern matching on that value
- Applying the value to an argument
- Using it as the first argument of
seq
The actual situation is slightly more complicated, but not in a way that matters here.
Furthermore, this forcing only occurs in the context of some outer expression, so rather than thinking of these as "forcing evaluation" in some abstract way, it helps to think of them as making the evaluation of the outer expression dependent on the evaluation of that value. This is why, for example, seq x x
does not force x
in any sense, since that's the final value of the expression anyway; it says that when the outer expression (whose value is x
) is evaluated, it should also evaluate x
, which is redundant.
Finally, any value that depends on forcing an undefined value is itself undefined.
Going through each expression:
seq undef1 () = undefined
In this case undef1
is undefined, and seq undef1 x
is an expression whose value is x
and depends on evaluating undef1
. So the expression as a whole is undefined as well no matter what the second argument to seq
is.
seq undef2 () = ()
In this case, undef2
is not undefined, but the result of applying it is. seq undef2 x
is an expression whose value is x
and depends on evaluating undef2
. This causes no problems, and the first argument to seq
is discarded, so the value of the expression is ()
here.
undef2 () = undefined
In this case, we're applying undef2
directly. The expression undef2 ()
depends on the evaluation of undef2
(which is fine) and evaluates to the result of applying undef2
, which in this case is undefined
.
Contrast this with a fourth case:
undef1 () = undefined
In this case, we're applying undef1
, so the value of the expression depends on evaluating undef1
, which is undefined and therefore so is the whole expression. This is the same "value" as the previous expression using undef2
, but for a very different reason!