Verklaar een luie evaluatie-gril

Ik lees het boek van Hadley Wickhams op Github, in het bijzonder dit deel op luie evaluatie. Daar geeft hij een voorbeeld van de gevolgen van luie evaluatie, in het deel met add/adders-functies. Laat me dat stukje citeren:

Deze [luie evaluatie] is belangrijk bij het maken van sluitingen met lapply of een lus:

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

x wordt lui geëvalueerd de eerste keer dat je een van de optellers aanroept
functies. Op dit punt is de lus voltooid en de uiteindelijke waarde van
x is 10. Daarom zullen alle optelfuncties 10 optellen bij hun
input, waarschijnlijk niet wat je wilde! Evaluatiecorrecties handmatig forceren
het probleem:

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

Ik schijn dat stukje niet te begrijpen, en de uitleg daar is minimaal. Kan iemand dat specifieke voorbeeld uitwerken en uitleggen wat daar gebeurt? Ik ben vooral verbaasd over de zin “op dit punt is de lus voltooid en is de uiteindelijke waarde van x 10”. Welke lus? Welke eindwaarde, waar? Het moet iets simpels zijn dat ik mis, maar ik zie het gewoon niet. Bij voorbaat hartelijk dank.


Antwoord 1, autoriteit 100%

Dit is niet langer het geval vanaf R 3.2.0!

De corresponderende regel in het wijzigingslogboekluidt:

Functies van hogere orde, zoals de Apply-functies en Reduce() now
argumenten forceren voor de functies die ze toepassen om te elimineren
ongewenste interacties tussen luie evaluatie en variabele capture
in sluitingen.

En inderdaad:

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

Antwoord 2, autoriteit 63%

Het doel van:

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

is het maken van een lijst met add-functies, de eerste voegt 1 toe aan de invoer, de tweede voegt 2 toe, enz. Luie evaluatie zorgt ervoor dat R wacht met het maken van de adders-functies totdat je echt begint de functies aanroepen. Het probleem is dat na het maken van de eerste optelfunctie, xwordt verhoogd met de lapply-lus, eindigend op een waarde van 10. Wanneer u de eerste optelfunctie aanroept, wordt luie evaluatie bouwt nu de functie en krijgt de waarde van x. Het probleem is dat de oorspronkelijke xniet langer gelijk is aan één, maar aan de waarde aan het einde van de lapply-lus, d.w.z. 10.

Daarom zorgt een luie evaluatie ervoor dat alle adderfuncties wachten tot nadat de lapply-lus is voltooid met het daadwerkelijk bouwen van de functie. Daarna bouwen ze hun functie met dezelfde waarde, namelijk 10. De oplossing die Hadley voorstelt is om xdirect te laten evalueren, om luie evaluatie te vermijden en de juiste functies te krijgen met de juiste xwaarden.

Other episodes