webentwicklung-frage-antwort-db.com.de

Was bedeutet das Ausrufezeichen in einer Haskell-Erklärung?

Ich bin auf die folgende Definition gestoßen, als ich versuchte, Haskell mithilfe eines realen Projekts zu erlernen, um es zu steuern. Ich verstehe nicht, was das Ausrufezeichen vor jedem Argument bedeutet, und meine Bücher schienen es nicht zu erwähnen.

data MidiMessage = MidiMessage !Int !MidiMessage
242
David

Es ist eine Strenge Erklärung. Grundsätzlich bedeutet dies, dass bei der Erstellung des Datenstrukturwerts eine Bewertung auf die so genannte "schwache normale Kopfform" erfolgen muss. Schauen wir uns ein Beispiel an, damit wir sehen können, was dies bedeutet:

data Foo = Foo Int Int !Int !(Maybe Int)

f = Foo (2+2) (3+3) (4+4) (Just (5+5))

Die oben angegebene Funktion f gibt bei der Auswertung ein "Thunk" zurück, dh den Code, der ausgeführt werden muss, um seinen Wert zu ermitteln. Zu diesem Zeitpunkt existiert noch nicht einmal ein Foo, nur der Code.

Aber irgendwann kann jemand versuchen, hinein zu schauen, wahrscheinlich durch eine Musterübereinstimmung:

case f of
     Foo 0 _ _ _ -> "first arg is zero"
     _           -> "first arge is something else"

Dies wird genug Code ausführen, um das zu tun, was es braucht, und nicht mehr. Es wird also ein Foo mit vier Parametern erstellt (weil Sie nicht hineinschauen können, ohne dass es existiert). Das erste, da wir es testen, müssen wir bis zu 4 Auswerten, wo wir feststellen, dass es nicht passt.

Der zweite muss nicht bewertet werden, da wir ihn nicht testen. Anstatt 6 An diesem Speicherort zu speichern, speichern wir nur den Code für eine mögliche spätere Auswertung, (3+3). Das wird nur dann zu einer 6, wenn sich jemand das ansieht.

Der dritte Parameter hat jedoch ein ! Vor sich und wird daher streng ausgewertet: (4+4) Wird ausgeführt und 8 Wird an diesem Speicherort gespeichert.

Der vierte Parameter wird ebenfalls streng ausgewertet. Aber hier wird es etwas knifflig: Wir bewerten nicht vollständig, sondern nur mit einer schwachen normalen Kopfform. Dies bedeutet, dass wir herausfinden, ob es sich um Nothing oder Just handelt, und das speichern, aber wir gehen nicht weiter. Das bedeutet, dass wir nicht Just 10, Sondern tatsächlich Just (5+5) speichern und den Thunk unbewertet lassen. Dies ist wichtig zu wissen, obwohl ich denke, dass alle Implikationen davon den Rahmen dieser Frage sprengen.

Sie können Funktionsargumente auf die gleiche Weise mit Anmerkungen versehen, wenn Sie die Spracherweiterung BangPatterns aktivieren:

f x !y = x*y

f (1+1) (2+2) gibt den Thunk (1+1)*4 zurück.

290
Curt J. Sampson

Ein einfacher Weg, um den Unterschied zwischen strengen und nicht strengen Konstruktorargumenten zu erkennen, besteht darin, wie sie sich verhalten, wenn sie undefiniert sind. Gegeben

data Foo = Foo Int !Int

first (Foo x _) = x
second (Foo _ y) = y

Da das nicht strenge Argument nicht von second ausgewertet wird, ist die Übergabe von undefined kein Problem:

> second (Foo undefined 1)
1

Aber das strikte Argument kann nicht undefined sein, auch wenn wir den Wert nicht verwenden:

> first (Foo 1 undefined)
*** Exception: Prelude.undefined
81
Chris Conway

Ich glaube, es ist eine Annotation der Strenge.

Haskell ist eine reine und faule funktionale Sprache, aber manchmal kann der Aufwand für Faulheit zu groß oder zu verschwenderisch sein. Daher können Sie den Compiler bitten, die Argumente für eine Funktion vollständig auszuwerten, anstatt die Thunks zu analysieren.

Es gibt weitere Informationen auf dieser Seite: Leistung/Strenge .

25
Chris Vest