Ich kenne zwei Möglichkeiten, um die Spezifikation einer Schnittstelle von einer Implementierung dieser Schnittstelle in Haskell zu trennen:
geben Klassen ein, z. B .:
RandomGen
StdGen
Datensätze, z.B.:
Network.Transport
Network.Transport.TCP
FRAGE 1: Wann ist es angebracht, das eine oder das andere zu verwenden?
FRAGE 2: Welche anderen Möglichkeiten gibt es, Interface / impl in Haskell zu trennen?
Die Antwort auf Frage 1 ist ziemlich einfach: Die beiden Optionen sind äquivalent - Typklassen können nur auf Datentypen "entzuckert" werden. Die Idee wurde in Ссылка beschrieben und diskutiert / p>
Die Antwort auf Frage 2 ist, dass diese beiden die einzigen Möglichkeiten sind, die Schnittstelle von der Implementierung zu trennen. Die Begründung wäre etwa so:
CanFoo
) neben nur der Typ-Signatur ( a -> Foo
) CanFoo
, aber mit mehr Feldern); Beachten Sie, dass ein Datensatz in diesem Kontext nur ein benannter Tupeltyp mit benannten Feldern ist. - Ob Funktionen explizit oder implizit (mit Typklassen) weitergegeben werden sollen, ist, wie bereits gezeigt wurde, konzeptionell ein und dasselbe [1] .
Hier ist eine einfache Demonstration, wie die 2 Methoden äquivalent sind:
%Vor%Wie Sie sehen können, wenn Sie Datensätze verwenden, werden Ihre "Instanzen" nicht mehr automatisch gesucht und müssen stattdessen explizit an die Funktionen übergeben werden, die sie benötigen.
Beachten Sie auch, dass die Record-Methode im trivialen Fall auf das Umgehen von Funktionen reduziert werden kann, da das Umgehen von CanFoo { foo = \_ -> Foo }
wirklich dasselbe ist wie das Umgehen der umschlossenen Funktion \_ -> Foo
selbst.
[1]
Tatsächlich wird diese begriffliche Äquivalenz in Scala offensichtlich, da eine Typklasse in Scala in Form eines Typs (z. B. trait CanFoo[T]
), einer Anzahl von Werten dieses Typs und Funktionsparametern dieses Typs codiert ist markiert als implicit
, was dazu führt, dass Scala Werte vom Typ CanFoo[Int]
an der Aufrufstelle nachschlägt.
Tags und Links haskell interface typeclass polymorphism