F# 有严格的评估策略。这意味着参数在传递给函数之前会被评估。因此,2/0=1在将其传递给您的-->函数之前对其进行评估,因此短路||不会影响 的评估2/0=1,因为它是在之前评估的||。
您需要将函数(-->运算符)转换为按名称而不是按值获取参数。实际上,这意味着使其采用() -> 'Tor 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)
为了进一步减少为每个参数创建 lambda 的样板,您可以尝试使用代码引用(以及像Unquote这样的库来评估它们):
let (-->) p q = (not (eval p)) || (eval q)
<@ false @> --> <@ 2 / 0 = 1 @>