奇怪的行为定义意味着F#中的运算符

S.N*_*.N. 2 f#

我尝试在F#中定义我自己的逻辑隐含运算符,如下所示

let (-->) p q = (not p) || q
Run Code Online (Sandbox Code Playgroud)

但是当我真正试用它时,似乎没有实现短路OR

> false --> ((2/0)=1);;
System.DivideByZeroException: Attempted to divide by zero.at <StartupCode$FSI_0015>.$FSI_0015.main@()
Stopped due to error
> 
Run Code Online (Sandbox Code Playgroud)

它不应该评估结果,但它是

有谁能看到这里有什么问题?我在VS 2012中运行F#

Bru*_*eis 10

当你写的时候a --> b,真正发生的是调用一个-->用2个参数调用的函数,ab.该运营商的语法只是一些语法糖.

在调用函数之前,运行时必须评估该函数的所有参数.因此,在调用之前-->,它首先进行评估false然后进行评估(2/0)=1.在评估最后一个表达式时,它会抛出异常.你的隐含函数永远不会被调用!

在其他一些语言中,例如Haskell,你有懒惰的评价.也就是说,只有在函数内实际访问函数的参数时,才会计算函数的参数.您可以通过不传递值来模拟它,但是传递一个计算结果为该值的函数,或者调用它的thunk.

注意,要在F#(thunks)中实现这种功能,必须稍微修改该函数:它必须调用 thunk来获取其值,就像John Palmer给出的示例一样:

let --> p q = (not p) || q()
let thunk = (fun _ -> ((2/0)=1))
false --> thunk
Run Code Online (Sandbox Code Playgroud)

注意在implies运算符q()的定义中的函数调用.如果你没有在第二个参数上给它一个thunk,它将不再起作用!


Lee*_*Lee 6

您还可以使用lazy按需评估第二个参数:

let (-->) p (q: Lazy<bool>) = (not p) || q.Force()
Run Code Online (Sandbox Code Playgroud)

你可以称之为:

false --> (lazy (2/0=1))
Run Code Online (Sandbox Code Playgroud)