Возврат анонимных функций от lapply — что не так?

При попытке создать список похожих функций с помощью lapply я обнаружил, что все функции в списке идентичны и равны тому, каким должен быть последний элемент.

Рассмотрим следующее:

pow <- function(x,y) x^y
pl <- lapply(1:3,function(y) function(x) pow(x,y))
pl
[[1]]
function (x) 
pow(x, y)
<environment: 0x09ccd5f8>

[[2]]
function (x) 
pow(x, y)
<environment: 0x09ccd6bc>

[[3]]
function (x) 
pow(x, y)
<environment: 0x09ccd780>

Когда вы пытаетесь оценить эти функции, вы получаете идентичные результаты:

pl[[1]](2)
[1] 8
pl[[2]](2)
[1] 8
pl[[3]](2)
[1] 8

Что здесь происходит и как я могу получить желаемый результат (правильные функции в списке)?


person James    schedule 01.04.2013    source источник
comment
Я не уверен, какова ваша цель. Может pl <- function(x,y) lapply(y,function(y) pow(x,y)); pl(2,1:3)?   -  person Roland    schedule 01.04.2013
comment
Эти заметки Росса Ихаки (RCore) могут оказаться полезными (в частности, часть о ленивом вычислении) www.stat.auckland.ac.nz/~ihaka/downloads/Waikato-WRUG.pdf   -  person Ricardo Saporta    schedule 01.04.2013
comment
Обратите внимание, что это уже не так, начиная с R 3.2.0, см. мой ответ ниже.   -  person jhin    schedule 29.04.2015


Ответы (2)


R передает обещания, а не сами ценности. Обещание принудительно выполняется при первой оценке, а не при передаче, и к тому времени индекс изменился, если кто-то использует код в вопросе. Код можно записать следующим образом для force обещание в момент вызова внешней анонимной функции и чтобы читателю было понятно:

pl <- lapply(1:3, function(y) { force(y); function(x) pow(x,y) } )
person G. Grothendieck    schedule 01.04.2013
comment
Спасибо, приятно знать, как работает эта ловушка. Я должен буду иметь это в виду в будущем. - person James; 02.04.2013

Начиная с версии R 3.2.0, это уже не так!

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

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

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

pow <- function(x,y) x^y
pl <- lapply(1:3,function(y) function(x) pow(x,y))
pl[[1]](2)
# [1] 2
pl[[2]](2)
# [1] 4
pl[[3]](2)
# [1] 8
person jhin    schedule 22.04.2015