Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Order of evaluation for short-circuit operators and let in OCaml

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.

like image 968
anol Avatar asked Oct 17 '25 17:10

anol


2 Answers

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.

like image 143
Virgile Avatar answered Oct 19 '25 11:10

Virgile


Evaluation is not lazy, so f and g will be evaluated before they are applied as arguments to your function.

like image 39
nlucaroni Avatar answered Oct 19 '25 12:10

nlucaroni