Wenn Sie eine Vergleichsfunktion erstellen, die ihre Argumente verfolgt, wie dies in GHCi der Befehlszeile ein:
> :module + Data.List Debug.Trace
> let myCompare x y = trace ("\tCmp " ++ show x ++ " " ++ show y) $ compare x y
dann können Sie das Verhalten sehen Sie selbst:
> sortBy myCompare "foobar"
" Cmp 'f' 'o'
Cmp 'o' 'b'
Cmp 'f' 'b'
Cmp 'a' 'r'
Cmp 'b' 'a'
a Cmp 'b' 'r'
b Cmp 'f' 'o'
Cmp 'f' 'r'
f Cmp 'o' 'o'
Cmp 'o' 'r'
o Cmp 'o' 'r'
or"
Haskell ist die Bewertung der Zeichenfolge lazily , ein Zeichen zu einer Zeit. Die linke Spalte wird gedruckt, während jedes Zeichen gefunden wird, wobei die rechte Spalte die erforderlichen Vergleiche aufzeichnet, wie durch "Trace" gedruckt.
Beachten Sie, dass Sie, wenn Sie dies kompilieren, insbesondere mit Optimierungen, möglicherweise ein anderes Ergebnis erhalten. Der Optimierer führt einen Striktheitsanalysator durch, der wahrscheinlich bemerkt, dass der gesamte String gedruckt wird, so dass es effizienter wäre, ihn eifrig zu bewerten.
versuchen Dann
> head $ sortBy myCompare "foobar"
Cmp 'f' 'o'
Cmp 'o' 'b'
Cmp 'f' 'b'
Cmp 'a' 'r'
Cmp 'b' 'a'
'a'
Wenn Sie verstehen wollen, wie dies funktioniert, den Quellcode für die Sortierfunktion nachschlagen und bewerten ‚sortieren‚foobar‘‘ manuell auf Papier.
qsort [] = []
qsort (x:xs) = qsort less ++ [x] ++ qsort greater
where (less, greater) = partition (< x) xs
So
qsort ('f':"oobar")
= qsort ('b':"a") ++ "f" ++ qsort ('o':"or")
= ("a" ++ "b") ++ "f" ++ qsort ('o':"or")
Und jetzt haben wir genug getan, um zu finden, dass ‚a‘ ist das erste Element in dem Ergebnis, ohne den anderen Aufruf zur „qsort“ zu bewerten. Ich habe den eigentlichen Vergleich weggelassen, weil er im Aufruf von "Partition" versteckt ist. Eigentlich ist "Partition" auch faul, also wurde das Argument zum anderen "qsort" nicht so weit ausgewertet, wie ich es gezeigt habe.Diese
Dieser letzte Teil ist falsch; Compiler können keine Absicht ableiten! – porges
Porges: Während der Compiler in bestimmten Fällen fest verdrahtet werden kann, um die Absicht zu analysieren, müssen Sie ** nicht * ableiten *. Sie müssen mechanisch einen Satz verwenden, der bewiesen hat, dass die optimierte Version des Codes mathematisch der ursprünglichen Version entspricht. Funktionale Sprachen erleichtern diesen Satz, indem sie Nebenwirkungen verbieten. –
Möglicherweise, aber ich kenne keine Haskell-Compiler, die automatische Theorembeweiser als Teil ihres Optimierungspasses enthalten. Der Grund, warum diese Zusammensetzung von Funktionen funktioniert, liegt einzig und allein an der Standardfaulheit von Haskell. – porges