2015-06-20 10 views
8

Warum ist wieWarum "iteriert" das Prelude nicht den Knoten?

iterate :: (a -> a) -> a -> [a] 
iterate f x = xs where xs = x : map f xs 

im Prelude nicht iterate definiert?

+1

Es ist erwähnenswert, dass Ihr Link GHC-Implementierung ist. Sie könnten sehr praktisch einen Compiler schreiben, der so 'iterate' implementiert. Die Leute hinter GHC wollten einfach nicht. –

Antwort

11

Das Binden des Knotens scheint die Freigabe nicht zu erhöhen.

Contrast mit:

cycle xs = let x = xs ++ x in x 

die Knoten hier Bindung hat den Effekt, eine kreisförmige verkettete Liste in einem Speicher zu schaffen. x ist ein eigener Schwanz. Es gibt einen echten Gewinn.

Ihre vorgeschlagene Implementierung erhöht die Freigabe nicht gegenüber der naiven Implementierung. Und dafür gibt es keine Möglichkeit - es gibt keine gemeinsame Struktur in so etwas wie iterate (+1) 0.

+0

Danke. Aber es gibt eine geteilte Struktur in, sagen wir, iterate (0 :) [] '. Behandelt diese iterate diesen Fall richtig? – user3237465

+0

manchmal Sharing ist kein Gewinn, sondern ein Verlust, wenn es die Speicherung der Struktur im Speicher verursacht, die andernfalls verworfen werden könnte (wenn es nur einen Verbraucher gibt, wie zum Beispiel 'print'). Wenn das der Fall ist, ist eine Rekursion gegenüber einer Corcursion vorzuziehen. –

+0

@WillNess 'iterate' erzeugt immer eine unendliche Liste. Es wird immer auf Corcursion beruhen. – Carl

2

Die Prelude-Definition, die ich unten zur Verdeutlichung mit einschließe, benötigt keinen Overhead, um die Karte aufzurufen.

iterate f x = x : iterate f (f x) 

Just for fun, ich habe ein kleines schnelles Programm testen Sie Ihre iterate vs der Prelude - nur zur normalen Form zu reduzieren take 100000000 $ iterate (+1) 0 (Dies ist eine Liste von Int s). Ich lief nur 5 Tests, aber Ihre Version lief für 7.833 (max 7.873 min 7.667) während der Prelude war 7.519 (max 7.591 min 7.477). Ich vermute, der Zeitunterschied ist der Overhead von map, der angerufen wird.

Der zweite Grund ist einfach: Lesbarkeit.

6

In Ihrer Version gibt es keine Knotenbindung, es wird lediglich ein Zeiger auf der erzeugten Liste gehalten, um den Eingabewert für die nächste Iteration zu finden. Dies bedeutet, dass jede Listenzelle nicht gc-ediert werden kann, bis die nächste Zelle erzeugt ist.

dagegen die Version des Prelude verwendet iterate ‚s Aufrufrahmen für das, und da es nur einmal gebraucht wird, könnte ein guter Compiler wiederverwenden, dass ein Rahmen und mutiert den Wert darin, für mehr optimierten Betrieb insgesamt (und die Liste der Zellen sind in diesem Fall unabhängig voneinander).

Verwandte Themen