Promises в lapply/R
Я не уверен, что делают promises в R
Если вы запустите
a = lapply(seq_len(2), function(n) { function() {n}})
b = lapply(seq_len(2), function(n) {n})
мы можем видеть, что
a[[1]]() # == 2
b[[1]] # == 1
Я понимаю, что R использует объект обещания и лениво оценивает выражение в своей среде, но я не понимаю, почему разные среды, созданный для каждой функции, не будет содержать их собственного значения для n.
[[1]]
function ()
{
n
}
<environment: 0x7f9b2416ad18>
[[2]]
function ()
{
n
}
<environment: 0x7f9b2416ab20>
as.list(environment(a[[1]]))
$n
[1] 2
as.list(environment(a[[2]]))
$n
[1] 2
Можно ли как-то зафиксировать семантику через функцию lapply?
lapply
function (X, FUN, ...)
{
FUN <- match.fun(FUN)
if (!is.vector(X) || is.object(X))
X <- as.list(X)
.Internal(lapply(X, FUN))
}
<bytecode: 0x7f9b25150f18>
<environment: namespace:base>
PS: вопрос с обратной фокусировкой
Изменить: можно ли написать функцию lapply2, которая в общем случае "заставляет" аргумент иметь единообразное поведение, как в:
pl <- lapply (1:3, function(y) { force(y); function(x) pow(x,y) } )
pl <- lapply2(1:3, function(y) { function(x) pow(x,y) } )
Ответы
Ответ 1
Мне легче понять в этой форме:
f=function(n) {function() {n}}
x=1
a=f(x)
x=2
a()
[1] 2
Ключевой частью документации является
Когда функция вызывается, аргументы сопоставляются, а затем каждая из формальные аргументы связаны с обещанием. Выражение, которое было для этого формального аргумента и указателя на окружающую среду вызываемая функция из хранится в обещании.
После вызова a=f(x)
аргумент функции n
привязан к обещанию с именем x
и указателем на глобальную среду .GlobalEnv
.
В ваших примерах lapply
анонимная функция function(n) { function() {n}}
вызывается из глобальной среды каждый раз. Вот почему каждый элемент списка a
получает одно и то же значение n
: он поступает из глобальной среды. Я не вижу, как можно изменить это поведение, переписывая lapply.
Ответ 2
Недавно я опубликовал комментарий о том, что это может иметь место в случае последних версий R
, но здесь также является официальным доказательством того, что lapply
теперь ведет себя точно так же, как ваша версия lapply2
, взятая из пресс-релиз R
3.2.0.
- Функции более высокого порядка, такие как функции apply и Reduce(), теперь приводят аргументы к функциям, которые они применяют, чтобы устранить нежелательные взаимодействия между ленивой оценкой и захватом переменной в закрытии. Это разрешает PR # 16093.