F # generische Typ-Constraints und Duck-Typisierung

7

Ich versuche, Ente Eingabe in F # zu implementieren, und ich entdeckte, dass Sie eine Member-Einschränkung in haben können F # Generika wie folgt:

%Vor%

Der obige Code wird jedoch nicht kompiliert, wenn ich versuche, die Eigenschaft zu referenzieren. Ich erhalte einen Compilerfehler:

  

Dieser Code ist nicht ausreichend generisch. Die Typvariable ^ T wenn ^ T   : (member get_Name: ^ T - & gt; string) konnte nicht generalisiert werden, weil   es würde seinem Umfang entgehen.

Ist es möglich, die Duck-Typisierung über eine generische Constraint zu implementieren?

    
Noel Kennedy 22.10.2012, 12:48
quelle

3 Antworten

19

In letzter Zeit gab es eine ähnliche Frage, wo Memberbeschränkungen in der Typdeklaration verwendet wurden .

Ich bin mir nicht sicher, wie ich das Beispiel korrigieren soll, um es kompilieren zu lassen, aber ich wäre nicht überrascht, wenn das nicht möglich wäre. Member-Constraints sind für die Verwendung mit statisch aufgelösten Typparametern und insbesondere mit inline functions oder members gedacht und ich denke nicht, dass es idiomatischer F # -Code ist, sie mit Typparametern einer Klasse zu verwenden.

Ich denke, dass eine idiomatische Lösung für Ihr Beispiel wäre, eine Schnittstelle zu definieren:

%Vor%

(Tatsächlich benötigt der ListEntryViewModel wahrscheinlich keinen Typparameter und kann einfach INamed als Konstruktorparameter verwenden, aber es kann ein Vorteil sein, ihn auf diese Weise zu schreiben.)

Nun können Sie immer noch die Enttippung verwenden und ListEntryViewModel für Dinge verwenden, die Name Eigenschaft haben, aber nicht die INamed Schnittstelle implementieren! Dies kann durch Schreiben einer inline -Funktion erfolgen, die INamed zurückgibt und statische Membereinschränkungen verwendet, um die vorhandene Eigenschaft Name einzufangen:

%Vor%

Sie können dann Ihr Ansichtsmodell erstellen, indem Sie ListEntryViewModel(namedModel someObj) schreiben, wobei someObj die Schnittstelle nicht implementieren muss, sondern nur die Eigenschaft Name benötigt.

Ich würde diesen Stil bevorzugen, weil Sie mit einer Schnittstelle besser dokumentieren können, was Sie vom Modell erwarten. Wenn Sie andere Objekte haben, die nicht zum Schema passen, können Sie sie anpassen. Wenn Sie jedoch ein Modell schreiben, ist die Implementierung einer Schnittstelle eine gute Möglichkeit, um sicherzustellen, dass alle erforderlichen Funktionen verfügbar sind.

    
Tomas Petricek 22.10.2012, 13:02
quelle
6
  

Ist es möglich, die Duck-Typisierung über eine generische Constraint zu implementieren?

Nein. Bis auf einige Spezialfälle implementiert F # nur eine nominale Eingabe, bei der die Eingabe von Enten nicht möglich ist. Wie die anderen Antworten erklärt haben, besteht die idiomatische "Lösung" darin, eine Schnittstelle zu allen Klassen nachzurüsten, die Sie an diese Schnittstelle gehalten haben, aber das ist natürlich in den meisten Fällen, in denen Sie Ente tippen möchten, unpraktisch.

>

Beachten Sie, dass diese Einschränkung in F # von .NET geerbt wird. Wenn Sie eine praktischere Lösung sehen möchten, die mit der Eingabe von Enten vergleichbar ist, sollten Sie sich die strukturell typisierten polymorphen Varianten und Objekte von OCaml ansehen.

    
Jon Harrop 23.10.2012 08:54
quelle
5

Damit der ursprüngliche Code funktioniert:

%Vor%

Sie müssen also das Element als "inline" markieren und die Abhängigkeit in der Elementfunktion wiederholen.

Ich stimme Tomas zu, dass ein Interface-basierter Ansatz normalerweise in F # bevorzugt wird.

    
wmeyer 22.10.2012 17:04
quelle

Tags und Links