Объясните ленивую причуду оценки
Я читаю книгу Хэдли Уикхэмс о Github, в частности эта часть на ленивую оценку. Там он приводит пример последствий ленивой оценки, в части с add/adders
функции. Позвольте мне процитировать этот кусочек:
эта [ленивая оценка] важна при создании замыканий с помощью lapply или цикла:
add <- function(x) { function(y) x + y } adders <- lapply(1:10, add) adders[[1]](10) adders[[10]](10)
x лениво вычисляется при первом вызове одного из сумматоров функции. На данный момент, цикл полное и окончательное значение x - это 10. Поэтому все функции сумматора добавят 10 на их вход, вероятно, не то, что вы хотели! Исправление принудительной оценки вручную проблема:
add <- function(x) { force(x) function(y) x + y } adders2 <- lapply(1:10, add) adders2[[1]](10) adders2[[10]](10)
Я, кажется, не понимаю, что бит, и объяснение там минимально. Не мог бы кто-нибудь уточнить этот конкретный пример и объяснить, что там происходит? Я особенно озадачен предложением "в этот момент цикл завершен и конечное значение x это 10". Какая петля? Какое конечное значение, где? Должно быть что-то простое мне не хватает, но я просто не вижу этого. Заранее большое спасибо.
2 ответа:
цель:
adders <- lapply(1:10, function(x) add(x) )
создать список
add
функции, первый добавляет 1 к его входу, второй добавляет 2 и т. д. Ленивая оценка заставляет R ждать реального создания функций сумматоров, пока вы действительно не начнете вызывать функции. Проблема в том, что после создания первой функции сумматора,x
увеличивается наlapply
цикл, заканчивающийся на 10. Когда вы вызываете первую функцию сумматора, ленивая оценка теперь строит функцию, получая значениеx
. Проблема в том, что оригиналx
больше не равно единице, а значению в концеlapply
петля, т. е. 10.таким образом, ленивая оценка заставляет все функции сумматора ждать, пока после
lapply
цикл завершился в действительно построении функции. Затем они строят свою функцию с тем же значением, т. е. 10. Решение, которое предлагает Хэдли, - это заставитьx
быть оцененным сразу, во избежание ленивая оценка, и получать правильно функции с правильнымx
значения.
это больше не верно по состоянию на R 3.2.0!
соответствующая строка в изменение входа гласит:
функции более высокого порядка, такие как функции apply и Reduce() теперь принудительные аргументы к функциям, которые они применяют для устранения нежелательные взаимодействия между отложенной оценкой и захватом переменных в закрытиях.
и действительно:
add <- function(x) { function(y) x + y } adders <- lapply(1:10, add) adders[[1]](10) # [1] 11 adders[[10]](10) # [1] 20