不能在F#中重载布尔运算符

时间:2011-02-15 09:57:04

标签: f# operator-overloading boolean

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

警告(在静态成员(||)定义上):名称'(||)'不应用作成员名称。如果定义静态成员以供其他CLI语言使用,则改为使用名称“op_BooleanOr”。

错误(在'let b3'语句中的b1和b2上):此表达式应该具有bool类型,但这里有类型MyBool

如果我使用op_BooleanOr而不是(||)警告消失,但错误仍然存​​在。

当我对MyInt类型中的+运算符执行完全相同的操作时,没有警告或错误。那么,当我尝试重载||时,为什么会出现这些警告/错误或&&?

2 个答案:

答案 0 :(得分:6)

我担心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

可以使用静态成员约束来定义两个运算符,因此它们(原则上)应该适用于实现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

然后,您可以使用所有必需的运算符定义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

答案 1 :(得分:4)

&&||与其他运算符的不同之处在于它们是短路的,因此无法简单地实现为方法。因此.net定义了special rules,您需要遵循这些内容以启用&&||与您自己的类型的使用。

简而言之:您还需要定义operator trueoperator false