Haskell: Wie trennt man die Schnittstelle von der Implementierung?

8

Ich kenne zwei Möglichkeiten, um die Spezifikation einer Schnittstelle von einer Implementierung dieser Schnittstelle in Haskell zu trennen:

  1. geben Klassen ein, z. B .:

  2. Datensätze, z.B.:

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?

    
haroldcarr 19.12.2015, 16:51
quelle

1 Antwort

3

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:

    Letztlich ist es das Ziel, Funktionen irgendwie zu umgehen - weil Haskell in keiner Weise etwas anderes als Funktionen implementieren kann. Um Implementierungen zu umgehen, müssen Sie also Funktionen weitergeben (beachten Sie, dass die Spezifikationen sind) nur Typen)
  1. Sie können entweder eine einzelne Funktion oder mehrere Funktionen
  2. weitergeben
  3. um eine einzelne Funktion zu übergeben, übergeben Sie einfach diese Funktion, oder diese Funktion in etwas eingewickelt, um Typklassen nachzuahmen (dh um Ihrer Schnittstelle einen Namen zu geben (zB CanFoo ) neben nur der Typ-Signatur ( a -> Foo )
  4. Um mehrere Funktionen zu umgehen, geben Sie sie einfach innerhalb eines Tupels oder eines Datensatzes weiter (wie unser 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.

%Vor%     
Erik Allik 20.12.2015, 01:05
quelle