2014-05-23 44 views
2

在OCaml中,當使用let爲短路運營商(&&||)分配別名時,它不再短路評估操作數。評估短路運營商的評估順序以及在OCaml中允許

這並不直觀。這種行爲的原因是什麼?

考慮下面的代碼:

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' *) 

這也發生與let ... in,所以let b = (&&) in b (f()) (g());;還輸出gf

回答

4

這是因爲&&是一個原始操作符,它的語義與普通函數有很大不同。實際上,(&&)或多或少等於fun x y -> x && y,正如nlucaroni所解釋的那樣,它將在它們被應用之前評估它的論點(以未指定的順序,通常是從右到左,但是你不應該依賴它)。

你可以看到,通過使用ocaml -dlambda。這將啓動一個解釋器,以您輸入的每個命令的一種中間語言輸出翻譯。然後,你就會有以下結果:

# (&&);; 
(function prim/1044 prim/1043 (&& prim/1044 prim/1043)) 
- : bool -> bool -> bool = <fun> 

lambda格式沒有記載,但它應該是再清楚不過的是ETA膨脹正在發生的事情。

+1

我從來沒有嘗試過-dlambda通過ocaml toplevel,很好。 – nlucaroni

2

評估不是懶惰的,所以fg將被評估之前它們作爲參數應用於您的函數。

+0

但是手冊(http://caml.inria.fr/pub/docs/manual-ocaml/expr.html#sec138)表示運算符'&&'和'||'是特殊的(短路),他們在第一個例子中表現得如此。該手冊還指出:*注意:操作符&&,||和〜 - 是專門處理的,不建議改變它們的含義。*但似乎並不清楚爲什麼'let'會干擾這一點。 – anol

+0

因爲'let'並不特別。 '外部a:bool - > bool - > bool =「%sequand」'雖然可以工作。 – nlucaroni

+0

@nlucaroni這對OCaml 4.01來說並不適合我,事實上我想說定義一個表現這種行爲的函數是不太可能的(當然,使用'bool Lazy,t'參數的時候很少)。 '&&'是一個由運行時特別處理的原始操作符。 – Virgile