2012-12-05 3 views
5

Ich habe eine sehr harte Zeit Verständnis für Lazyness Arbeit und wie der Cache funktioniert.Schritt-für-Schritt-Beispiel eines Lazy-Seq

Ich denke, dass ein Schritt-für-Schritt-Beispiel eines Lazy-Seq bei der Arbeit hier wirklich helfen könnte. Zum Beispiel habe ich die folgende Frage lesen:

Clojure lazy sequence usage

aber es ist noch nicht klar.

Meine Frage wäre, wie der Anruf feststellt, ob ein anderer Anruf einem zwischengespeicherten Anruf "gleicht" und wie lange er im Cache verbleibt? Ich habe versucht, (Quelle faul-seq) aber anscheinend ist es in Java Land, so dass ich Pech habe hier.

Für eine einfache Lazy-Seq, mit nur einem Argument (wie sagen die Liste der Potenzen von zwei), was ist, wenn ich es mit 5 und dann 8 nennen? Werden nur diese beiden Werte zwischengespeichert?

Und was ist der Zweck beim Erstellen und Caching einer unendlichen Liste, um eine unendliche Struktur zu erhalten, wenn ich den Speicher ruinieren werde, indem ich jede Eingabe zwischenspeichern werde, die ich bereits als Lazy-Funktion bezeichnet habe?

Weil es sagt, es speichert das Ergebnis bei jedem folgenden Aufruf ... Mit einem 's'.

1: Ergebnis für Argument ist '1' 2 zwischengespeichert: Ergebnis für Argument seines '2' im Cache gespeichert 3: Ergebnis für Argument gecached '3' zu sein ... 2 30: Ich zählte bis zu 2 30 und es ist großartig, weil ich faul bin und alle, aber jetzt gibt es einen 2 ** 30 Cache im Speicher alle vorherigen Anrufe für alle die nachfolgenden Aufrufe zwischenspeichern.

oder ist es nur der letzte Anruf, der zwischengespeichert wird?

Was ist, wenn ich eine Lazy-Funktion schreibe, die Bäume als Argumente nimmt? Läuft es ist gleich? über das Argument übergeben, um zu wissen, ob es eine neue Auswertung geben muss?

Kann dieses Verhalten zur Laufzeit irgendwie verfolgt werden?

Antwort

8

Die ‚Cache‘ in einer faulen Sequenz ist kein wandelbar Cache, die Dinge abläuft, wie Sie in einer Webapp verwenden würden, es ist ein Cache der Größe ein, und es gibt eine in jeder Zelle in der Liste. Dieser "Cache" enthält entweder einen Wert oder den Code, um den Wert zu berechnen, und niemals beides. Sobald er den Wert berechnet, speichert er den Wert (in dieser Zelle/Eintrag) und wenn jemand die Zelle erneut liest, gibt er ihnen den Wert direkt, anstatt den Code aufzurufen.

hier ist eine vereinfachte imaginäre repl Sitzung den Punkt zu illustrieren:

user> (def a (range)) 
a = [code-for-rest] 
user> (first a) 
a = [code-for-first, code-for-rest] 
a = [0, code-for-rest] 
result=> 0 
user> (first a) 
a = [0, code-for-rest] 
result=> 0 
user> (nth a 10) 
a = [0]->[1]->[2]->[3]->[4]->[5]->[6]->[7]->[8]->[9, code-for-rest] 
result=> 4 

In diesem Beispiel jede Zelle enthält anfangs (und dies ist eine Vereinfachung nur diesen Punkt zu illustrieren), um den Code, um den Wert zu generieren und die Code, um den Rest der Liste zu generieren (oder Null, wenn dies das Ende der Liste ist). Sobald diese Zelle realisiert (unlazy) wird, ersetzt sie ihren Inhalt durch den tatsächlichen Wert, so dass sie nun den Wert und den Code enthält, um den Rest der Sequenz zu generieren. Wenn die nächste Zelle in der Liste gelesen wird, wird sie zuerst durch Code-für-Rest (wie in der Zelle enthalten) erzeugt, dann erzeugt der Code-für-n-te in der neuen Zelle den Wert für diese Zelle.

+0

+1, dank viel ..., was im Fall von "intertwinned" geschieht, ruft die Funktion lazy (Sagen wir: "nth a 50", dann "nth a 100", dann "nth a 80", dann "nt h a 150 ")? Und was ist mit Calls für diese Funktion, die aus verschiedenen Threads bestehen? Hat jeder Thread einen Cache der Größe eins? –

+0

@CedricMartin Lazy Seqs, wie alle anderen Clojure-Datenstrukturen, sind unveränderlich und somit threadsicher, so dass der gespeicherte Wert nach der Berechnung für alle Threads freigegeben wird. Es kann hilfreich sein, einen faulen Seq als einen Zeiger in eine verkettete Liste zu betrachten (das ist genau das, was er ist), nur der Schwanz der Liste berechnet den nächsten Zeiger nicht, bis jemand danach fragt. – Alex

+0

Der 'Cache' befindet sich buchstäblich in der Zelle der Liste. Es ist keinem bestimmten Thread zugeordnet. –

1

Hier haben Sie ein Spielzeug Beispiel, das, was passiert während der Laufzeit zeigt:

(defn times-two[number] 
(print "- ") 
(* 2 number)) 

(def powers-of-two (lazy-cat [1 2] (map times-two (rest powers-of-two)))) 

(println (take 10 powers-of-two)) 
(println (take 12 powers-of-two)) 

Die Ausgabe sollte:

(1 - 2 - 4 - 8-16 - 32-64 - 128 - 256 512)

(1 2 4 8 16 32 64 128 256 - 512 - 1024 2048)