我尝试在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个参数调用的函数,a和b.该运营商的语法只是一些语法糖.
在调用函数之前,运行时必须评估该函数的所有参数.因此,在调用之前-->,它首先进行评估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,它将不再起作用!
您还可以使用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)