8

我知道 F# 有 MAP,但我想使用 .NET 字典。这个字典有作为字符串的键和作为 F# 值 + 字典的值,即:

type ExprC = 
    | StrC of string
    | BoolC of bool
    | IntC of int32
    | DecC of decimal
    | ArrayC of int * array<ExprC>
    | RelC of RelationC
and RelationC = Dictionary<string, ExprC>        

现在,我要解决的问题是如何为 RelationC 类型提供结构平等。如果需要封装实际存储,如何创建一个替代 Dictionary 的容器,将其用于可变操作并具有结构相等性?


使用当前答案,此代码不起作用(诅咒实现不完整,但是,这甚至无法编译):

[<CustomEquality; CustomComparison>]
type MyDict() =
    inherit Dictionary<string, ExprC>()
    override this.Equals x =
        match x with
        | :? MyDict as y -> (this = y)
        | _ -> false

    override this.GetHashCode () =
        hash this

    interface System.IComparable with
      member x.CompareTo yobj =
          match yobj with
          | :? MyDict as y -> compare x y
          | _ -> invalidArg "MyDict" "cannot compare values of different types"

and [<StructuralEquality;StructuralComparison>] ExprC =
    | IntC of int
    | StrC of string
    | MapC of MyDict

这是错误:

错误 FS0377:此类型使用了“NoEquality”、“ReferenceEquality”、“StructuralEquality”、“NoComparison”和“StructuralComparison”属性的无效组合 (FS0377)

4

2 回答 2

3

如果你绝对必须使用Dictionary<string, ExprC>,你可以派生Dictionary<'k, 'v>并覆盖Equals

type MyDict() =
    inherit Dictionary<string, ExprC>()
    override this.Equals x =
        true // real implementation goes here
    override this.GetHashCode () =
        0 // real implementation goes here

在这里,您需要实施Equals以实现结构平等,并且您需要实施GetHashCode以匹配您的Equals实施。

如果您不需要具体类Dictionary<'k, 'v>,另一种选择是定义您自己的实现类IDictionary<TKey, TValue>

虽然可能,但这听起来需要做很多工作。使用 a 会容易得多Map,默认情况下它具有结构相等性:

let m1 = Map.ofList [("foo", 1); ("bar", 2); ("baz", 3)]
let m2 = Map.ofList [("bar", 2); ("foo", 1); ("baz", 3)]
let m3 = Map.ofList [("bar", 2); ("foo", 1); ("baz", 4)]

> m1 = m2;;
val it : bool = true
> m1 = m3;;
val it : bool = false
于 2016-01-25T07:19:18.707 回答
2

关于更新原帖末尾的问题:“这种类型使用无效的组合......”的原因是什么?这是 F# 编译器中的一个错误,错误信息具有误导性,请参阅 Github。解决方案是简单地从MyDict.

于 2016-11-23T13:33:09.537 回答