在带有元组的区分联合上重载等式F#运算符会产生意外结果

时间:2014-06-27 03:27:31

标签: .net f# functional-programming operator-overloading equality

好的,这样可以使复杂的标题更清晰:我有一个单例联盟,它是一个通用的元组。该类型还重载了相等运算符,意图使Edge (1, 2)等同于Edge (2, 1)

type Edge<'a> = Edge of 'a * 'a
    with
        static member (=) (e1: Edge<_>, e2: Edge<_>) =
            match e1, e2 with
            | Edge(a,b), Edge(c,d) ->
                (a = c && b = d) || (a = d && b = c)

但是,当我创建两个应该等效的Edge类型值并进行比较时,它会返回false。

> let e1 = Edge (1,2);;

val e1 : Edge<int> = Edge (1,2)

> let e2 = Edge (2,1);;

val e2 : Edge<int> = Edge (2,1)

> e1 = e2;;

val it : bool = false

我对这里发生的事情感到茫然。有没有特别关于equality(=)运算符的东西,它使覆盖比其他运算符更复杂?

1 个答案:

答案 0 :(得分:4)

所以错误信息中有一个提示(你没有发帖)

  

警告FS0086:名称'(=)'不应用作成员名称。      要为类型定义相等语义,请覆盖“Object.Equals”成员。      如果要定义静态成员以供其他CLI语言使用,请改为使用名称“op_Equality”。

您实际上可以通过在原始代码中添加printf次来检查,然后您会发现它实际上从未被调用过。

那么你试试这个:

type Edge<'a> = Edge of 'a * 'a
     with
         override x.Equals (y: obj ) =
             match  y with
             | :? Edge<'a> as e ->
                 match x,e with
                 |Edge(a,b),Edge(c,d)->(a = c && b = d) || (a = d && b = c)
             | _ -> false

也失败了。然后编译器错误消息将引导您完成一些错误消息,直到您进入

[<CustomEquality;NoComparison>]
type Edge<'a when 'a:equality> = Edge of 'a * 'a
    with
        override x.Equals (y: obj ) =
            match  y with
            | :? Edge<'a> as e ->
                match x,e with
                |Edge(a,b),Edge(c,d)->(a = c && b = d) || (a = d && b = c)
            | _ -> false

效果很好。 equals函数比许多其他运算符稍微复杂一些,因此覆盖它需要花费更多的精力。