Wie der Titel schon sagt: Welche Garantien gibt es für die Bewertung einer Haskell-Funktionsrückgabeeinheit? Man könnte meinen, dass in einem solchen Fall keine Auswertung erforderlich ist. Der Compiler könnte alle derartigen Aufrufe durch einen unmittelbaren ()
Wert ersetzen, es sei denn, es liegen explizite Anforderungen an die Strenge vor. In diesem Fall muss der Code möglicherweise entscheiden, ob dies der Fall sein soll Rückkehr ()
oder Boden.
Ich habe in GHCi damit experimentiert, und es scheint, dass das Gegenteil passiert, das heißt, eine solche Funktion scheint bewertet zu werden. Ein sehr primitives Beispiel wäre
f :: a -> ()
f _ = undefined
Die Auswertung f 1
löst aufgrund des Vorhandenseins von einen Fehler aus undefined
, sodass definitiv eine Auswertung erfolgt. Es ist jedoch nicht klar, wie tief die Bewertung geht; manchmal scheint es so tief zu gehen, wie es notwendig ist, alle Aufrufe von zurückkehrenden Funktionen auszuwerten ()
. Beispiel:
g :: [a] -> ()
g [] = ()
g (_:xs) = g xs
Dieser Code wird auf unbestimmte Zeit wiederholt, wenn er mit angezeigt wird g (let x = 1:x in x)
. Aber dann
f :: a -> ()
f _ = undefined
h :: a -> ()
h _ = ()
kann verwendet werden, um zu zeigen, dass die h (f 1)
Rückgabe ()
erfolgt. In diesem Fall werden also nicht alle Unterausdrücke mit Einheitswert ausgewertet. Was ist hier die allgemeine Regel?
ETA: Natürlich weiß ich etwas über Faulheit. Ich frage, was Compiler-Autoren daran hindert, diesen speziellen Fall noch fauler als gewöhnlich zu machen.
ETA2: Zusammenfassung der Beispiele: GHC scheint ()
genau wie jeder andere Typ zu behandeln , dh als ob es eine Frage gäbe, welcher reguläre Wert, der den Typ bewohnt, von einer Funktion zurückgegeben werden sollte. Die Tatsache, dass es nur einen solchen Wert gibt, scheint von den Optimierungsalgorithmen nicht (ab) verwendet zu werden.
ETA3: Wenn ich Haskell sage, meine ich Haskell-wie im Bericht definiert, nicht Haskell-the-H-in-GHC. Scheint eine Annahme zu sein, die nicht so weit verbreitet ist, wie ich es mir vorgestellt habe (was "von 100% der Leser" war), oder ich hätte wahrscheinlich eine klarere Frage formulieren können. Trotzdem bedauere ich, den Titel der Frage geändert zu haben, da ursprünglich gefragt wurde, welche Garantien für eine solche Funktion bestehen.
ETA4: Es scheint, dass diese Frage ihren Lauf genommen hat, und ich halte sie für unbeantwortet. (Ich suchte nach einer Funktion zum Schließen von Fragen, fand aber nur "Beantworte deine eigene Frage" und da diese nicht beantwortet werden kann, ging ich diesen Weg nicht.) Niemand brachte etwas aus dem Bericht hervor, das es so oder so entscheiden würde , was ich versucht bin, als starke, aber nicht eindeutige Antwort „Keine Garantie für die Sprache als solche“ zu interpretieren. Wir wissen nur, dass die aktuelle GHC-Implementierung die Bewertung einer solchen Funktion nicht überspringen wird.
Beim Portieren einer OCaml-App nach Haskell ist das eigentliche Problem aufgetreten. Die ursprüngliche App hatte eine gegenseitig rekursive Struktur vieler Typen, und der Code deklarierte eine Reihe von Funktionen, die assert_structureN_is_correct
in 1..6 oder 7 für N aufgerufen wurden, von denen jede Einheit zurückgab, wenn die Struktur tatsächlich korrekt war, und eine Ausnahme auslöste, wenn dies nicht der Fall war . Außerdem haben sich diese Funktionen gegenseitig aufgerufen, da sie die Korrektheitsbedingungen zerlegt haben. In Haskell wird dies besser mit der Either String
Monade gehandhabt , also habe ich es so transkribiert, aber die Frage als theoretisches Problem blieb bestehen. Vielen Dank für alle Eingaben und Antworten.
f 1
wird undefined
in allen Fällen durch "ersetzt" .
... -> ()
kann 1) beenden und zurückgeben ()
, 2) mit einem Ausnahme- / Laufzeitfehler beenden und nichts zurückgeben oder 3) divergieren (unendliche Rekursion). GHC optimiert den Code nicht unter der Annahme, dass nur 1) passieren kann: Wenn dies angefordert f 1
wird, überspringt es nicht seine Auswertung und kehrt zurück ()
. Die Haskell-Semantik besteht darin, sie zu bewerten und zu sehen, was unter 1,2,3 passiert.
()
In dieser Frage gibt es wirklich nichts Besonderes (weder den Typ noch den Wert). Alle die gleichen Beobachtungen passieren , wenn Sie ersetzen () :: ()
mit, sagen wir, 0 :: Int
überall. Dies sind alles nur langweilige alte Konsequenzen einer faulen Bewertung.
()
Typ ()
und undefined
.
h1::()->() ; h1 () = ()
und zu vergleichen, um den Unterschied zu beobachtenh2::()->() ; h2 _ = ()
. Führen Sie beideh1 (f 1)
und aush2 (f 1)
und sehen Sie, dass nur der erste verlangt(f 1)
.