How to make a .NET Mutable Dictionary <T, T> with Structural Comparison and Equality in F #
I know that F # has a MAP, but I want to use the .NET Dictionary. This dict has the key as a string and the values โโas F # + dict values, i.e.:
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> Now the problem I want to solve is how to provide the RelationC type with structural equality. If you want to encapsulate the actual storage, how to create a container that is a replacement for the dictionary, use it for mutable operations and have structural equality?
This code does not work with the current answer (the implementation curse is not completed, however it does not even compile):
[<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 xy | _ -> invalidArg "MyDict" "cannot compare values of different types" and [<StructuralEquality;StructuralComparison>] ExprC = | IntC of int | StrC of string | MapC of MyDict This is mistake:
Error FS0377: This type uses an invalid combination of the attributes "NoEquality", "ReferenceEquality", "StructuralEquality", "NoComparison" and "StructuralComparison" (FS0377)
If you absolutely must use Dictionary<string, ExprC> , you can get from Dictionary<'k, 'v> and override Equals :
type MyDict() = inherit Dictionary<string, ExprC>() override this.Equals x = true // real implementation goes here override this.GetHashCode () = 0 // real implementation goes here Here you need to implement Equals to have structural equality, and you need to implement GetHashCode to match the Equals implementation.
Another alternative, if you do not need a specific Dictionary<'k, 'v> class, is to define your own class that implements IDictionary<TKey, TValue> .
While this is possible, it sounds like a lot of work. It would be much easier to use a Map , which by default has structural equality:
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 Regarding the question at the end of the updated original post: What is the reason "This type uses an invalid mix ..."? This is a bug in the F # compiler, the error message is misleading, see Github . The solution is to simply remove all attributes from MyDict .