Ich bin gespannt, wie dieser Code zu optimieren:Optimierung der Teilberechnung in Haskell
fun n = (sum l, f $ f0 l, g $ g0 l)
where l = map h [1..n]
Unter der Annahme, dass f
, f0
, g
, g0
und h
alle teuer sind, aber die Erstellung und Speicherung von l
extrem ist teuer.
Wie beschrieben, l
wird gespeichert, bis das zurückgegebene Tupel vollständig ausgewertet oder Müll gesammelt wird. Stattdessen sollten length l
, f0 l
und g0 l
alle ausgeführt werden, wenn einer von ihnen ausgeführt wird, aber f
und g
sollten verzögert werden.
fun n = a `seq` b `seq` c `seq` (a, f b, g c)
where
l = map h [1..n]
a = sum l
b = inline f0 $ l
c = inline g0 $ l
Oder die sehr ähnlich:
Es scheint könnte dieses Verhalten durch schriftlich fixiert werden
Wirfun n = (a,b,c) `deepSeq` (a, f b, g c)
where ...
vielleicht eine Reihe von internen Typen angeben könnten auch die gleichen Effekte zu erzielen, was schmerzhaft aussieht. Gibt es noch andere Möglichkeiten?
Auch hoffe ich natürlich mit meinem inline
s, dass der Compiler Sicherungen sum
, f0
und g0
in eine einzige Schleife, und verbraucht durch Begriff l
Begriff konstruiert. Ich könnte dies durch manuelles Inlining explizit machen, aber das wäre scheiße. Gibt es Möglichkeiten, explizit zu verhindern, dass die Liste l
jemals erstellt und/oder inlining gezwungen wird? Pragmas, die Warnungen oder Fehler erzeugen, wenn Inlining oder Fusion während des Kompilierens fehlschlagen?
Als beiseite, ich bin neugierig, warum seq
, inline
, lazy
usw. sind alle definiert durch let x = x in x
im Vorspiel. Ist das nur, um ihnen eine Definition zu geben, damit der Compiler sie überschreiben kann?
Als Antwort auf die letzte Frage: http://stackoverflow.com/a/8654407/1011995 –
Sind 'f0' und' g0' völlig willkürlich, oder können sie in Bezug auf 'foldr' geschrieben werden? – dave4420
Würde hier nicht eine einfache Faltung mit einem (a, b, c) -Behälter ausreichen? – Sarah