F#有嚴格的評估策略。這意味着參數在傳遞給函數之前被評估。因此,2/0=1
在傳遞到您的-->
函數之前進行評估,因此||
的短路不會影響2/0=1
的評估,因爲在||
之前評估該評估。
您需要將您的函數(-->
運算符)轉換爲按名稱而不是按值的參數。實際上,這意味着,使其採取任何() -> 'T
或Lazy<'T>
:
let (-->) p q = (not <| p()) || q()
> (fun() -> false) --> (fun() -> 2/0=1);;
true
,或者使用內置的lazy
結構。這種方式可以達到同樣的效果(前提是您的計算不依賴於副作用)有位更簡潔的語法:
let (-->) (p : Lazy<_>) (q : Lazy<_>) = (not <| p.Force()) || q.Force()
> lazy false --> lazy (2/0 = 1)
true
它的工作,但它看上去並不是很方便。不幸的是,我認爲有擺脫fun() -> ...
沒有簡單的方法,但我認爲你可以通過定義一些常量有點減少樣板:
let True, False = (fun() -> true), (fun() -> false)
爲進一步減少每個參數創建拉姆達的樣板,你可以嘗試使用代碼報價(和圖書館像Unquote以評估它們):
let (-->) p q = (not (eval p)) || (eval q)
<@ false @> --> <@ 2/0 = 1 @>
@ MisterMetaphor - 這無關與評價的順序;這與渴望與懶惰評估是正交的。 –
@OnorioCatenacci,你說得對,我想我的意思是評估策略。謝謝。 – MisterMetaphor