F# 有严格的评估策略。这意味着参数在传递给函数之前会被评估。因此,2/0=1
在将其传递给您的-->
函数之前对其进行评估,因此短路||
不会影响 的评估2/0=1
,因为它是在之前评估的||
。
您需要将函数(-->
运算符)转换为按名称而不是按值获取参数。实际上,这意味着使其采用() -> 'T
or 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 @>