Не совсем уверен, так ли это, но я думаю, что это связано с ленивой оценкой.Основная идея состоит в том, что R не оценивает выражение, когда оно не используется.В вашем примере rlang::expr( !!i )
является самооценкой, потому что выражение, представляющее константу, является самой константой.Это приводит к тому, что на каждой итерации цикла for выполняется следующее:
X <- list()
for( i in 1:3 )
X[[i]] <- rlang::expr( !!i )
Обратите внимание, что элементы X
больше не являются выражениями, а являются целыми числами:
> str(X)
List of 3
$ : int 1
$ : int 2
$ : int 3
identical(rlang::expr(1),1)
# [1] TRUE
Ваш второй примероднако имеет rlang::expr( 1 + (!!i) )
, которое остается выражением на каждой итерации цикла for без вычисления.Ленивая оценка заставляет R оценивать только i
только в конце цикла, который принимает последнее значение i
.Способ устранения этой проблемы - force
оценка i
:
Y <- list()
for( i in 1:3 ){
force(i)
Y[[i]] <- rlang::expr( 1 + (!!i) )
}
> str(Y)
List of 3
$ : language 1 + 1L
$ : language 1 + 2L
$ : language 1 + 3L
Обратите внимание, что ленивая оценка также влияла на такие функции, как lapply
, как обсуждалось в этом вопросе: Объяснителенивая оценка , но с тех пор она была исправлена в R 3.2.0.Функции высшего порядка, такие как lapply
, теперь передают аргументы внутренней функции.Смотрите ответ @ jhin в том же вопросе.Вот почему решение @Mike Badescu lapply
теперь работает.