Подтвердить что ты не робот

Объясните ленивую оценочную причуду

Я читаю книгу Хэдли Уикхэма на Github, в частности эту часть на ленивую оценку. Там он приводит пример последствий ленивой оценки в части с функциями add/adders. Позвольте мне процитировать этот бит:

Эта [ленивая оценка] важна при создании замыканий с помощью лаппеля или цикла:

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". Какой цикл? Какое окончательное значение, где? Должно быть, что-то простое, что мне не хватает, но я просто этого не вижу. Большое спасибо заранее.

4b9b3361

Ответ 1

Цель:

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

заключается в создании списка функций add, первый добавляет 1 к его входу, второй добавляет 2 и т.д. Ленивая оценка заставляет R ждать действительно создания функций сумматоров, пока вы действительно не начнете вызывать функции. Проблема в том, что после создания первой функции сумматора x увеличивается на цикл lapply, заканчивающийся на значение 10. Когда вы вызываете первую функцию сумматора, ленивая оценка теперь строит функцию, получая значение x. Проблема в том, что исходный x больше не равен единице, а соответствует значению в конце цикла lapply, т.е. 10.

Следовательно, ленивая оценка заставляет все функции сумматора ждать до тех пор, пока цикл lapply не завершится при действительно построении функции. Затем они строят свою функцию с одинаковым значением, т.е. 10. Решение, которое предлагает Хэдли, заключается в том, чтобы заставить x оцениваться напрямую, избегая ленивой оценки и получая правильные функции с правильными значениями x.

Ответ 2

Это уже не так, как в R 3.2.0!

Соответствующая строка в журнале изменений читает:

Функции более высокого порядка, такие как применяемые функции и Reduce() теперь аргументы силы в отношении функций, которые они применяют для устранения нежелательные взаимодействия между ленивой оценкой и переменным захватом в закрытии.

И действительно:

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