Erzwingt Clojures Memo die Auswertung seiner Argumente?

8

Wenn ich in Clojure eine Funktion memoize, nenne sie f und rufe sie in einem Argument a auf.

Wenn a ein großer Lazy-Wert ist, gibt memoize einen Wert basierend auf dem Thunk-Vergleich zurück, anstatt die Auswertung von a zu erzwingen und das Ergebnis zu vergleichen?

Wo ein Thunk der unbewertete Teil der Lazy-Sequenz ist.

Wenn dies nicht der Fall ist, gibt es eine eingebaute Möglichkeit, dieses Verhalten zu erhalten?

Danke!

    
toofarsideways 01.02.2012, 00:27
quelle

2 Antworten

5

Wie von mikera angegeben, verarbeitet memoize keine unendlichen Lazy Seqs. Ich füge diese Antwort hinzu, um eine kurze Beschreibung der Implementierungsgründe dafür zu geben (plus zwei Ideen für identitätsbasierte Memo-Schemata, eine einfache, eine komplexe). (Bearbeiten: Tatsächlich gibt es eine einfache allgemeine identitätsbasierte Lösung, siehe unten.)

Warum es nicht funktioniert

memoize verwendet eine Hash-Map zum Speichern der Zuordnung von Argumenten zu Werten und Hash-Maps verwenden clojure.lang.Util/hasheq , wenn festgestellt wird, ob ein Objekt einer ihrer Schlüssel ist (außer leere Maps, die nur false zurückgeben). Da die Implementierung von hasheq für Lazy Seqs die Gesamtheit der Seqs erzwingt, fragt jede Map, ob eine unendliche Lazy Seq eine ihrer Schlüssel ist, dass sie in eine unendliche, Speicher erschöpfende Schleife geht. Das gleiche gilt für memoize .

Eigentlich ist die Karte zunächst eine Array-Map. (In Clojure sind kleine Maps aus Gründen der Effizienz in der Regel Array-Maps. Wenn genügend Elemente in einer Array-Map enthalten sind, wird der Rückgabewert zu einer Hash-Map.) Nicht leeres Array hingegen auch kann aus einem ähnlichen Grund, der eine Äquivalenzprüfmethode betrifft, keine unendlichen Lazy Seqs verarbeiten.

Eine Lösung

assoc gibt den Wert zurück, den System/identityHashCode für ein bestimmtes Objekt zurückgeben würde, wenn es die Standardimplementierung verwendet (unabhängig davon, ob hashCode überschrieben wird oder nicht).

%Vor%

Jetzt können Sie das tun (was mit dem normalen hashCode nicht funktionieren würde):

%Vor%

Ursprüngliche Diskussion alternativer Implementierungen folgt.

Ich glaube nicht, dass es eine integrierte Lösung gibt, die Zeigergleichheit verwendet. Um eine so allgemeine wie memoize zu implementieren, müssten Sie eine Map-Struktur mit Zeiger-Gleichheit-basierten Hashing implementieren (viz.% Co_de%). Oder Sie könnten einen einfachen "zuletzt verwendeten" Cache mit memoize erstellen.

    
Michał Marczyk 01.02.2012, 02:31
quelle
5

Memoize wird auf der Basis des Werts von jedem Argument, das Sie übergeben, Memoize.

Daher funktioniert memoize gut mit Lazy-Sequenzen als Argumente : da es den Wert der Sequenz betrachtet, wird es bei Bedarf erzwingen .

Dies bedeutet jedoch, dass Sie keine unendlichen Lazy-Sequenzen verwenden können , da die Verwendung von memoize die Auswertung dieser Variablen erzwingen kann, was eindeutig nicht gut enden wird.

    
mikera 01.02.2012 01:36
quelle