Erklären Sie eine faule Bewertungsspielchen

Ich lese Hadley Wickhams Buch über Github, insbesondere diesen Teil über faule Bewertung . Dort gibt er ein Beispiel für Folgen einer faulen Auswertung, im Teil mit add/adders . Lassen Sie mich das ein bisschen zitieren:

Diese [lazy evaluation] ist wichtig beim Erstellen von Closures mit Lapply oder einer Schleife:

 add <- function(x) { function(y) x + y } adders <- lapply(1:10, add) adders[[1]](10) adders[[10]](10) 

x wird beim ersten Aufruf einer der Addierfunktionen träge ausgewertet. An diesem Punkt ist die Schleife abgeschlossen und der Endwert von x ist 10. Daher addieren alle Addiererfunktionen 10 zu ihrer Eingabe, wahrscheinlich nicht das, was Sie wollten! Die manuelle Erzwingung der Auswertung behebt das Problem:

 add <- function(x) { force(x) function(y) x + y } adders2 <- lapply(1:10, add) adders2[[1]](10) adders2[[10]](10) 

Ich verstehe das nicht, und die Erklärung ist minimal. Könnte jemand bitte dieses spezielle Beispiel erläutern und erklären, was dort passiert? Ich bin besonders verwirrt durch den Satz “an diesem Punkt ist die Schleife abgeschlossen und der endgültige Wert von x ist 10”. Welche Schleife? Welcher Endwert, wo? Muss etwas sein, was ich vermisse, aber ich sehe es einfach nicht. Vielen Dank im Voraus.

Das Ziel von:

 adders < - lapply(1:10, function(x) add(x) ) 

ist eine Liste von add functionen zu erstellen, der erste fügt 1 zu seinem Eingang, der zweite fügt 2, etc. Faule Bewertung bewirkt, dass R auf das eigentliche Erstellen der Addierer-functionen warten, bis Sie wirklich beginnen, die functionen aufzurufen. Das Problem besteht darin, dass nach dem Erstellen der ersten lapply x um die lapply Schleife erhöht wird und auf einen Wert von 10 endet. Wenn Sie die erste Addiererfunktion aufrufen, erstellt die Lazy-Evaluierung jetzt die function und erhält den Wert von x . Das Problem ist, dass das ursprüngliche x nicht mehr eins ist, sondern dem Wert am Ende der lapply , dh 10.

Aus diesem lapply führt die Lazy-Evaluierung dazu, dass alle Addiererfunktionen bis zum lapply der lapply warten, bis sie wirklich aufgebaut sind. Dann bauen sie ihre function mit dem gleichen Wert auf, dh 10. Die Lösung, die Hadley vorschlägt, besteht darin, zu erzwingen, dass x direkt ausgewertet wird, wodurch eine faule Auswertung vermieden wird und die richtigen functionen mit den richtigen x Werten erhalten werden.

Dies gilt ab R 3.2.0 nicht mehr!

Die entsprechende Zeile im Änderungsprotokoll lautet:

functionen höherer Ordnung wie die functionen apply und Reduce () erzwingen nun Argumente für die functionen, die sie anwenden, um unerwünschte Interaktionen zwischen verzögerter Auswertung und Variablenerfassung in Schließungen zu eliminieren.

Und in der Tat:

 add < - function(x) { function(y) x + y } adders <- lapply(1:10, add) adders[[1]](10) # [1] 11 adders[[10]](10) # [1] 20