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.