7 Stimmen

Typerweiterungsfehler für Dictionary<'K, 'V>

Die folgende Typenerweiterung

module Dict =

  open System.Collections.Generic

  type Dictionary<'K, 'V> with
    member this.Difference(that:Dictionary<'K, 'T>) =
      let dict = Dictionary()
      for KeyValue(k, v) in this do
        if not (that.ContainsKey(k)) then
          dict.Add(k, v)
      dict

gibt den Fehler:

Die Signatur und die Implementierung sind nicht kompatibel, weil die Deklaration des Typparameters "TKey" eine Einschränkung der Form "TKey : equality" erfordert.

Aber wenn ich die Einschränkung hinzufüge, wird der Fehler angezeigt:

Die deklarierten Typparameter für diese Typerweiterung stimmen nicht mit den deklarierten Typparametern des ursprünglichen Typs 'Dictionary< überein. , >'

Dies ist besonders rätselhaft, weil die folgende Typenerweiterung diese Einschränkung nicht hat und funktioniert.

type Dictionary<'K, 'V> with
  member this.TryGet(key) =
    match this.TryGetValue(key) with
    | true, v -> Some v
    | _ -> None

Jetzt habe ich seltsame Gedanken: Ist die Einschränkung nur erforderlich, wenn auf bestimmte Mitglieder zugegriffen wird?

4voto

desco Punkte 16452
module Dict =

  open System.Collections.Generic

  type Dictionary<'K, 'V> with
    member this.Difference(that:Dictionary<'K, 'T>) =
        let dict = Dictionary(this.Comparer)
        for KeyValue(k, v) in this do
            if not (that.ContainsKey(k)) then
                dict.Add(k, v)
        dict

EDIT :

Gemäß F#-Spezifikation (14.11 Zusätzliche Beschränkungen für CLI-Methoden)

Einige spezifische CLI-Methoden und -Typen werden von F# besonders behandelt, da sie in der F#-Programmierung häufig vorkommen und extrem schwer zu findende Fehler verursachen. Für jede Verwendung der folgenden Konstrukte erlegt der F#-Compiler zusätzliche Ad-hoc-Beschränkungen auf:

  • x.Equals(yobj) erfordert Typ ty : equality für den statischen Typ von x
  • x.GetHashCode() erfordert Typ ty : equality für den statischen Typ von x
  • new Dictionary<A,B>() erfordert A : equality für jede Überladung, die nicht eine IEqualityComparer<T>

2voto

Random Dev Punkte 50772

Soweit ich sehen kann, erfüllt der folgende Code den Zweck:

module Dict =
open System.Collections.Generic

type Dictionary<'K, 'V> with
    member this.Difference(that: Dictionary<'K,'V2>) = 
        let diff =
            this
            |> Seq.filter (fun x -> not <| that.ContainsKey(x.Key))
            |> Seq.map (fun x -> x.Key, x.Value)
        System.Linq.Enumerable.ToDictionary(diff, fst, snd)

0voto

JaredPar Punkte 699699

Das Problem ist Ihre Verwendung des Add Methode. Wenn Sie diese Methode verwenden, um Dictionary<TKey, TValue> dann wird F# erzwingen, dass TKey hat die Gleichheitsbeschränkung.

Nachdem ich ein wenig herumgespielt habe, bin ich nicht sicher, ob es überhaupt möglich ist, diese Erweiterungsmethode zu schreiben. Das F#-Typsystem scheint zu erzwingen, dass der Deklarationstyp der Erweiterungsmethode keine zusätzlichen Einschränkungen als der ursprüngliche Typ hat (ich erhalte einen Fehler, wenn ich die equality Einschränkung). Außerdem darf der in den einzelnen Erweiterungsmethoden aufgeführte Typ nicht von dem aufgeführten Typ abweichen. Ich habe eine Reihe von Möglichkeiten ausprobiert und kann nicht erreichen, dass dies korrekt funktioniert.

Am nächsten komme ich mit der Methode ohne Verlängerung wie folgt

let Difference (this : Dictionary<'K, 'T>) (that:Dictionary<'K, 'T> when 'K : equality) =
    let dict = Dictionary()
    for KeyValue(k, v) in this do
        if not (that.ContainsKey(k)) then
            dict.Add(k, v)
    dict

Vielleicht kann mir ein anderer F#-Ninja das Gegenteil beweisen

0voto

Brian Punkte 115257

(EDIT: CKoenig hat eine gute Antwort.)

Hm, ich habe auch nicht sofort eine Möglichkeit gesehen, das zu tun.

Hier ist eine nicht typsichere Lösung, die andere vielleicht zu verrückten Ideen inspirieren kann.

open System.Collections.Generic  

module Dict =  
  type Dictionary<'K, 'V> with    
    member this.Difference<'K2, 'T when 'K2 : equality>(that:Dictionary<'K2, 'T>) =      
        let dict = Dictionary<'K2,'V>()      
        for KeyValue(k, v) in this do        
            if not (that.ContainsKey(k |> box |> unbox)) then          
                dict.Add(k |> box |> unbox, v)      
        dict

open Dict

let d1 = Dictionary()
d1.Add(1, "foo")
d1.Add(2, "bar")

let d2 = Dictionary()
d2.Add(1, "cheese")

let show (d:Dictionary<_,_>) =
    for (KeyValue(k,v)) in d do
        printfn "%A: %A" k v

d1.Difference(d2) |> show

let d3 = Dictionary()
d3.Add(1, 42)

d1.Difference(d3) |> show

let d4 = Dictionary()
d4.Add("uh-oh", 42)

d1.Difference(d4) |> show  // blows up at runtime

Insgesamt scheint es keine Möglichkeit zur Vereinheitlichung der Typen zu geben K y K2 ohne sie jedoch zu zwingen, dieselbe Gleichheitsbedingung zu erfüllen...

(EDIT: scheint wie Aufruf in .NET, die Gleichheit-Beschränkung-agnostische ist ein guter Weg, um ein Wörterbuch in Abwesenheit der zusätzlichen Einschränkung zu erstellen).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X