Ich las das Papier von Simon Peyton Jones, et al. benannt “Playing by the Rules: Rewriting as a practical optimization technique in GHC”. Im zweiten Abschnitt, nämlich “ Die Grundidee ” sie schreiben:Umschreiben als eine praktische Optimierungstechnik in GHC: Wird es wirklich benötigt?
Betrachten Sie die vertraute
map
Funktion, die eine Funktion auf jedes Element einer Liste gilt. Geschrieben in Haskell, siehtmap
wie folgt aus:
map f [] = []
map f (x:xs) = f x : map f xs
Nehmen wir nun an, dass der Compiler den folgenden Aufruf von
map
Begegnungen:
map f (map g xs)
Wir wissen, dass dieser Ausdruck entspricht zu
(wobei “. ” ist Funktionszusammensetzung), und wir wissen, dass der letztere Ausdruck effizienter ist als der erstere, weil es keine Zwischenliste gibt. Aber der Compiler hat kein solches Wissen.
Eine mögliche Erwiderung ist, dass der Compiler klüger sein sollte --- aber der Programmierer wird immer Dinge wissen, die der Compiler nicht herausfinden kann. Ein anderer Vorschlag ist dies: Erlaube dem Programmierer, dieses Wissen direkt dem Compiler mitzuteilen. Das ist die Richtung, die wir hier erkunden.
Meine Frage ist, warum können wir den Compiler nicht schlauer machen? Die Autoren sagen, dass “ aber der Programmierer immer Dinge wissen wird, die der Compiler ” nicht herausfinden kann. Allerdings, das ist keine gültige Antwort, weil der Compiler in der Tat herausfinden kann, dass map f (map g xs)
zu map (f . g) xs
äquivalent ist, und hier ist, wie:
map f (map g xs)
map g xs
mitmap f [] = []
vereint.Daher
map g [] = []
.map f (map g []) = map f []
.map f []
vereint mitmap f [] = []
.Daher
map f (map g []) = []
.map g xs
vereint mitmap f (x:xs) = f x : map f xs
.Daher
map g (x:xs) = g x : map g xs
.map f (map g (x:xs)) = map f (g x : map g xs)
.map f (g x : map g xs)
vereint mitmap f (x:xs) = f x : map f xs
.Daher
map f (map g (x:xs)) = f (g x) : map f (map g xs)
.
Daher haben wir jetzt die Regeln:
map f (map g []) = []
map f (map g (x:xs)) = f (g x) : map f (map g xs)
Wie Sie f (g x)
ist nur (f . g)
und map f (map g xs)
sehen kann, wird rekursiv aufgerufen werden. Dies ist genau die Definition von map (f . g) xs
. Der Algorithmus für diese automatische Konvertierung scheint ziemlich einfach zu sein. Warum also nicht das implementieren, statt die Regeln neu zu schreiben?
Es wäre hilfreich, wenn Sie mir ein konkretes Beispiel zeigen könnten Rewrite-Regeln sind besser als Inlining. –
Haben Sie sich das verlinkte Paper on Stream Fusion angeschaut? –