2016-01-24 11 views
7

Wiem, że F # ma MAP, ale chcę używać słownika .NET. Ten DICT mieć klucz jako ciąg i wartości jako # wartości F + dict, a mianowicie:Jak dokonać .NET Mutable Dictionary <T, T> z StructuralComparison & Equality w 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>   

Teraz problem chcę rozwiązać ten sposób zapewnić typ RelationC równości strukturalnej. Jeśli jest wymagane, aby enkapsulować rzeczywistą pamięć masową, jak utworzyć kontener zastępujący Słownik, użyć go do operacji zmiennych i mieć równość strukturalną?


Przy obecnym odpowiedź, ten kod nie działa (przekleństwo realizacja nie jest kompletna, to jednak nawet nie skompilować):

[<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 

Jest to błąd:

Error FS0377: This type uses an invalid mix of the attributes 'NoEquality', 'ReferenceEquality', 'StructuralEquality', 'NoComparison' and 'StructuralComparison' (FS0377)

+2

Z ciekawości, czy istnieje szczególny powód, dla którego chce się to zrobić za pomocą 'Dictionary' zamiast' Map'? – TheInnerLight

+0

Wydajność. Dicty .NET są o wiele szybsze (https://stackoverflow.com/questions/3396196/f-fsharpmap-vs-dictionary-performance). W moim przypadku użycia, będę potrzebował dużo. Plus, ciekawość. Myślę, że warto wiedzieć, w jaki sposób obrócić dobrego obywatela w klasę .NET;) – mamcx

+2

Czy profilowałeś i znalazłeś problem z wydajnością, czy też zgadłeś, że będzie problem w przyszłości? Jeśli nie wiesz na pewno, czy to jest problem, nie utrudniaj życia. Zrób to w oczywisty sposób i rozwiąż problem później, jeśli zajdzie taka potrzeba. – TheInnerLight

Odpowiedz

2

Jeśli absolutnie musi użyć Dictionary<string, ExprC>, możesz wyprowadzić z Dictionary<'k, 'v> i zastąpić Equals:

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

Tu trzeba by wdrożyć Equals mieć równości strukturalnej i trzeba wdrożyć GetHashCode dopasować Ci Equals realizację.

Inną alternatywą, jeśli nie potrzebujesz konkretnej klasy Dictionary<'k, 'v>, jest zdefiniowanie własnej klasy, która implementuje IDictionary<TKey, TValue>.

O ile to możliwe, brzmi to jak dużo pracy. Byłoby o wiele łatwiej użyć Map, który ma równości strukturalnej domyślnie:

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 
+0

Ponadto można zdefiniować strukturę zawierającą zmienne odniesienie do "mapy". Obliczenie równości stałoby się wtedy naprawdę łatwe. – CaringDev

+0

Jak to zrobić ze strukturą? – mamcx

+0

Nie można uzyskać z rodzaju wartości. –

1

Jeśli chodzi o pytanie na koniec zaktualizowanego oryginalnego postu: Co jest powodem „Ten typ wykorzystuje nieprawidłową mieszankę. .. "? To jest błąd w kompilatorze F #, komunikat o błędzie jest mylący, see Github. Rozwiązaniem jest po prostu usunięcie wszystkich atrybutów z MyDict.

Powiązane problemy