Ich bin über einige irritierende Dinge gestolpert. Ich weiß, dass Haskell mit schwacher Kopfnormalform (WHNF) funktioniert und ich weiß, was das ist. Geben Sie den folgenden Code in ghci ein (ich verwende den Befehl: sprint, der den Ausdruck meines Wissens auf WHNF reduziert.):
let intlist = [[1,2],[2,3]]
:sprint intlist
gibt intlist = _
das macht mir total Sinn.
let stringlist = ["hi","there"]
:sprint stringlist
gibt stringlist = [_,_]
diese bereits verwirrt mich. Aber dann:
let charlist = [['h','i'], ['t','h','e','r','e']]
:sprint charlist
überraschend gibt charlist = ["hi","there"]
Soweit ich Haskell verstanden habe, sind Zeichenfolgen nichts anderes als Listen von Zeichen, was durch Überprüfen der Typen "hi" :: [Char]
und bestätigt zu werden scheint ['h','i'] :: [Char]
.
Ich bin verwirrt, weil nach meinem Verständnis alle drei obigen Beispiele mehr oder weniger gleich sind (eine Liste von Listen) und daher auf den gleichen WHNF reduziert werden sollten, nämlich _. Was vermisse ich?
Vielen Dank
"bla"
und['b','l','a']
würde anders herauskommen."bla"
könnte überladen sein, ist aber['b','l','a']
bekanntermaßen einString
/[Char]
?['b', 'l', 'a']
es auch überladen sein könnte und ebenfalls"bla"
nur überladen ist, wenn-XOverloadedStrings
es eingeschaltet ist.Antworten:
Beachten Sie, dass
:sprint
sich nicht um einen Ausdruck zu WHNF reduzieren. Wenn dies der Fall wäre, würde Folgendes4
eher geben als_
:Nimmt vielmehr
:sprint
den Namen einer Bindung, durchläuft die interne Darstellung des Bindungswerts und zeigt die bereits "bewerteten Teile" (dh die Teile, die Konstruktoren sind) an, während sie_
als Platzhalter für nicht bewertete Thunks (dh die angehaltene Lazy-Funktion) verwendet werden Anrufe). Wenn der Wert vollständig nicht bewertet wird, wird keine Bewertung durchgeführt, auch nicht für WHNF. (Und wenn der Wert vollständig ausgewertet wird, erhalten Sie das, nicht nur WHNF.)Was Sie in Ihren Experimenten beobachten, ist eine Kombination aus polymorphen und monomorphen numerischen Typen, verschiedenen internen Darstellungen für Zeichenfolgenliterale im Vergleich zu expliziten Listen von Zeichen usw. Grundsätzlich beobachten Sie technische Unterschiede bei der Kompilierung verschiedener Literalausdrücke zu Bytecode. Die Interpretation dieser Implementierungsdetails als etwas, das mit WHNF zu tun hat, wird Sie also hoffnungslos verwirren. Im Allgemeinen sollten Sie
:sprint
nur als Debugging-Tool verwenden, nicht als Möglichkeit, sich mit WHNF und der Semantik der Haskell-Evaluierung vertraut zu machen.Wenn Sie wirklich verstehen möchten, was
:sprint
passiert, können Sie einige Flags in GHCi aktivieren, um zu sehen, wie Ausdrücke tatsächlich behandelt werden, und so schließlich zu Bytecode kompiliert werden:Danach können wir den Grund sehen, den Sie
intlist
angeben_
:Sie können den
returnIO
und den äußeren:
Aufruf ignorieren und sich auf den Teil konzentrieren, der mit beginnt((\ @ a $dNum -> ...
Hier
$dNum
ist das Wörterbuch für dieNum
Einschränkung. Dies bedeutet, dass der generierte Code den tatsächlichen Typa
im Typ noch nicht aufgelöst hatNum a => [[a]]
, sodass der gesamte Ausdruck weiterhin als Funktionsaufruf dargestellt wird, der ein (Wörterbuch für) einen geeignetenNum
Typ verwendet. Mit anderen Worten, es ist ein unbewerteter Thunk, und wir bekommen:Geben Sie andererseits den Typ als an
Int
, und der Code ist völlig anders:und so ist die
:sprint
Ausgabe:Ebenso haben Literalzeichenfolgen und explizite Zeichenlisten völlig unterschiedliche Darstellungen:
und die Unterschiede in der
:sprint
Ausgabe stellen Artefakte dar, von denen Teile des Ausdrucks, die GHCi als bewertet (explizite:
Konstruktoren) betrachtet, als nicht bewertet (dieunpackCString#
Thunks) betrachten.quelle