Hal*_*ema 2 f# boolean operator-overloading
F#确实允许像+这样的算术运算符的重载,但似乎不允许像||这样的布尔运算符.以下代码生成警告和两个错误:
type MyBool =
val Value : bool
new(value) = { Value = value }
static member (||) (v1: MyBool, v2 : MyBool) =
new MyBool(v1.Value || v2.Value)
let b1 = new MyBool(true)
let b2 = new MyBool(false)
let b3 = b1 || b2
Run Code Online (Sandbox Code Playgroud)
警告(在静态成员(||)定义上):名称'(||)'不应用作成员名称.如果定义静态成员以供其他CLI语言使用,则使用名称"op_BooleanOr"代替.
错误(在'let b3'语句中的b1和b2上):此表达式应该具有bool类型,但这里有类型MyBool
如果我使用op_BooleanOr而不是(||)警告消失,但错误仍然存在.
当我对MyInt类型中的+运算符执行完全相同的操作时,没有警告或错误.那么,当我尝试重载||时,为什么会出现这些警告/错误 要么 &&?
我担心F#编译器没有任何逻辑运算符处理方法可以覆盖它们(如C#那样).据我所知,x && y编译简单为if x then y else false,所以x必须是布尔值.我没有检查F#编译器是否支持C#中声明的类型的这种行为,但我不认为它.
据我所知,为您自己的运算符模拟短路behvaior的最佳方法是使用lazy关键字来创建惰性值.然后你可以这样写:
let foo b =
printfn "foo %b" b
MyBool(b)
lazy foo true &&! lazy foo false // Calls 'foo' for both branches
lazy foo false &&! lazy foo false // Calls 'foo' only for the first one
Run Code Online (Sandbox Code Playgroud)
这两个运算符可以使用静态成员约束来定义,因此它们(原则上)应该适用于实现C#所需的运算符的任何类型.
let inline (&&!) (x:Lazy<_>) (y:Lazy<_>) =
if (^T: (static member op_False : ^T -> bool) x.Value)
then x.Value else x.Value &&& y.Value
let inline (||!) (x:Lazy<_>) (y:Lazy<_>) =
if (^T: (static member op_False : ^T -> bool) x.Value)
then x.Value else x.Value ||| y.Value
Run Code Online (Sandbox Code Playgroud)
然后,您可以MyBool使用所有必需的运算符定义类型(作为旁注,如果您像这样定义它,它应该以自然的方式从C#中使用):
type MyBool(b) =
member x.Value = b
static member (|||) (v1: MyBool, v2 : MyBool) =
MyBool(v1.Value || v2.Value)
static member (&&&) (v1: MyBool, v2 : MyBool) =
MyBool(v1.Value && v2.Value)
static member op_True (v: MyBool) = v.Value
static member op_False (v: MyBool) = not v.Value
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
364 次 |
| 最近记录: |