Suche…


Bemerkungen

Eine der Stärken von Haskell ist die Möglichkeit, das Typsystem zur Modellierung von Teilen Ihrer Problemdomäne im Typsystem zu nutzen. Dabei begegnet man oft sehr komplexen Typen. Beim Schreiben von Programmen mit diesen Typen (dh mit Werten mit diesen Typen) wird es gelegentlich fast unveränderlich, alle Typen zu "jonglieren". Ab GHC 7.8 gibt es eine neue syntaktische Funktion, die als typisierte Bohrungen bezeichnet wird. Typisierte Bohrungen ändern die Semantik der Kernsprache nicht; Sie sind lediglich als Hilfsmittel für das Schreiben von Programmen gedacht.

Eine ausführliche Erklärung der typisierten Löcher sowie eine Erläuterung des Designs der typisierten Löcher finden Sie im Haskell-Wiki .


Abschnitt des GHC-Benutzerhandbuchs über typisierte Bohrungen .

Syntax von typisierten Löchern

Eine typisierte Lücke ist ein einzelner Unterstrich ( _ ) oder ein gültiger Haskell-Bezeichner, der sich nicht im Gültigkeitsbereich befindet, in einem Ausdruckskontext. Vor dem Vorhandensein von typisierten Löchern würden beide Dinge einen Fehler auslösen, sodass die neue Syntax nicht mit der alten Syntax interferiert.

Verhalten der typisierten Bohrungen kontrollieren

Standardmäßig erzeugen typisierte Bohrungen einen Fehler bei der Kompilierung, wenn eine typisierte Bohrung auftritt. Es gibt jedoch mehrere Flags, um ihr Verhalten zu optimieren. Diese Flags werden wie folgt zusammengefasst ( GHC-Trac ):

Standardmäßig hat GHC Bohrungen aktiviert und erzeugt einen Kompilierungsfehler, wenn eine typisierte Bohrung auftritt.

Wenn -fdefer-type-errors oder -fdefer-typed-holes aktiviert sind, werden -fdefer-typed-holes in Warnungen umgewandelt und führen bei der Auswertung zu Laufzeitfehlern.

Das Warnflag -fwarn-typed-holes ist standardmäßig aktiviert. Ohne -fdefer-type-errors oder -fdefer-typed-holes dieses Flag ein No-Op, da typisierte Löcher unter diesen Bedingungen ein Fehler sind. Wenn eines der Verzögerungsflags aktiviert ist (Konvertierung typisierter -fno-warn-typed-holes in Warnungen), deaktiviert das Flag -fno-warn-typed-holes die Warnungen. Dies bedeutet, dass die Kompilierung im Hintergrund erfolgreich ist und die Bewertung einer Lücke zu einem Laufzeitfehler führt.

Semantik typisierter Löcher

Der Wert einer Typ-Bohrung kann einfach als undefined , obwohl eine typisierte Bohrung einen Fehler bei der Kompilierung auslöst. Daher ist es nicht unbedingt erforderlich, ihr einen Wert zuzuweisen. Eine typisierte Bohrung (wenn sie aktiviert ist) erzeugt jedoch einen Fehler bei der Kompilierungszeit (oder eine Warnung mit Fehlern mit verzögertem Typ), der den Namen der typisierten Bohrung, den generell abgeleiteten Typ und die Typen der lokalen Bindungen angibt. Zum Beispiel:

Prelude> \x -> _var + length (drop 1 x)

<interactive>:19:7: Warning:
    Found hole `_var' with type: Int
    Relevant bindings include
      x :: [a] (bound at <interactive>:19:2)
      it :: [a] -> Int (bound at <interactive>:19:1)
    In the first argument of `(+)', namely `_var'
    In the expression: _var + length (drop 1 x)
    In the expression: \ x -> _var + length (drop 1 x)

Beachten Sie, dass im Fall von typisierten Löchern in Ausdrücken, die in den GHCi repl (wie oben) eingegeben wurden, auch der Typ des eingegebenen Ausdrucks wie it (hier vom Typ [a] -> Int ).

Verwenden von typisierten Löchern zum Definieren einer Klasseninstanz

Typisierte Bohrungen können die Definition von Funktionen durch einen interaktiven Prozess erleichtern.

Angenommen, Sie möchten eine Foo Bar Klasseninstanz definieren (für Ihren benutzerdefinierten Bar Typ, um sie mit einer polymorphen Bibliotheksfunktion zu verwenden, für die eine Foo Instanz erforderlich ist). Sie würden jetzt traditionell die Dokumentation von Foo nachschlagen, herausfinden, welche Methoden Sie definieren müssen, ihre Typen untersuchen usw. - aber mit typisierten Löchern können Sie das tatsächlich überspringen!

Zuerst definieren Sie einfach eine Dummy-Instanz:

instance Foo Bar where

Der Compiler wird sich jetzt beschweren

Bar.hs:13:10: Warning:
No explicit implementation for
  ‘foom’ and ‘quun’
In the instance declaration for ‘Foo Bar’

Ok, also müssen wir foom für Bar definieren. Aber was soll das überhaupt sein? Wir sind wieder zu faul, um in der Dokumentation nachzuschauen, und fragen den Compiler:

instance Foo Bar where
  foom = _

Hier haben wir ein typisiertes Loch als einfache "Dokumentationsanfrage" verwendet. Die Compiler-Ausgaben

Bar.hs:14:10:
    Found hole ‘_’ with type: Bar -> Gronk Bar
    Relevant bindings include
      foom :: Bar -> Gronk Bar (bound at Foo.hs:4:28)
    In the expression: _
    In an equation for ‘foom’: foom = _
    In the instance declaration for ‘Foo Bar’

Beachten Sie, wie der Compiler die Klassentypvariable bereits mit dem konkreten Typ Bar gefüllt hat, für den wir sie instanziieren möchten. Dadurch kann die Signatur viel einfacher verständlich werden als die polymorphe Signatur der Klassendokumentation, insbesondere wenn es sich um eine kompliziertere Methode handelt, z. B. eine Klasse mit mehreren Parametern.

Aber was zum Teufel ist Gronk ? An diesem Punkt ist es wahrscheinlich eine gute Idee, Hayoo zu fragen. Wir können jedoch auch ohne das Gronk a : Als blinde Vermutung nehmen wir an, dass dies nicht nur ein Gronk a sondern auch ein Einzelwertkonstruktor, dh er kann als Funktion verwendet werden, die irgendwie einen Gronk a Wert erzeugt. Also versuchen wir es

instance Foo Bar where
  foom bar = _ Gronk

Wenn wir Glück haben, ist Gronk tatsächlich ein Wert, und der Compiler wird jetzt sagen

    Found hole ‘_’
      with type: (Int -> [(Int, b0)] -> Gronk b0) -> Gronk Bar
    Where: ‘b0’ is an ambiguous type variable

Ok, das ist hässlich - zunächst einmal, dass Gronk zwei Argumente hat, also können wir unseren Versuch verfeinern:

instance Foo Bar where
  foom bar = Gronk _ _

Und das ist jetzt ziemlich klar:

    Found hole ‘_’ with type: [(Int, Bar)]
    Relevant bindings include
      bar :: Bar (bound at Bar.hs:14:29)
      foom :: Bar -> Gronk Bar (bound at Foo.hs:15:24)
    In the second argument of ‘Gronk’, namely ‘_’
    In the expression: Gronk _ _
    In an equation for ‘foom’: foom bar = Gronk _ _

Sie können nun weitere Fortschritte durch zB den Dekonstruktion bar - Wert (die Komponenten werden dann zeigen, mit Typen im Relevant bindings Abschnitt). Oft ist es an einem Punkt völlig klar, wie die richtige Definition aussehen wird, weil Sie alle verfügbaren Argumente sehen und die Typen wie ein Puzzle zusammenpassen. Oder Sie sehen alternativ, dass die Definition unmöglich ist und warum.

All dies funktioniert am besten in einem Editor mit interaktiver Compilation, z. B. Emacs mit Hash-Modus. Sie können dann typisierte Bohrungen ähnlich wie Abfragen mit dem Mauszeigerwert in einer IDE für eine interpretierte dynamische Imperativsprache verwenden, jedoch ohne alle Einschränkungen.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow