问题
In OCaml, when using a let
to assign an alias to a short-circuit operator (&&
or ||
), it no longer short-circuits evaluation of the operands.
This is not intuitive. What is the reason for this behavior?
Consider the following code:
let f() = Printf.printf "f"; false;;
let g() = Printf.printf "g"; true;;
let a = (&&);;
f() && g();; (* outputs 'f' *)
(&&) (f()) (g());; (* outputs 'f' *)
a (f()) (g());; (* outputs 'gf' *)
This also happens with let ... in
, so let b = (&&) in b (f()) (g());;
also outputs gf
.
回答1:
It's because &&
is a primitive operator whose semantics is quite different from a normal function. In fact, (&&)
is more or less equivalent to fun x y -> x && y
, which as explained by nlucaroni will evaluate its arguments before they are being applied (in an unspecified order, which happens to be usually right-to-left, but you should not rely on it).
You can see that by using ocaml -dlambda
. This will launch an interpreter which outputs the translation in one of the intermediate languages of each command you enter. Then, you'll have the following result:
# (&&);;
(function prim/1044 prim/1043 (&& prim/1044 prim/1043))
- : bool -> bool -> bool = <fun>
The lambda
format is not documented, but it should be clear enough that eta-expansion is happening.
回答2:
Evaluation is not lazy, so f
and g
will be evaluated before they are applied as arguments to your function.
来源:https://stackoverflow.com/questions/23833221/order-of-evaluation-for-short-circuit-operators-and-let-in-ocaml