Разница между тем, что делает with(list(x = 42), f())
, и тем, что вы ожидаете, - это разница между лексической областью видимости (что и используется в R) и динамической областью видимости (которая, кажется, вы ожидаете).
Лексическое определение объема означает, что свободные переменные (например, переменная x
в f
) ищутся в среде, где f
равно , определено , а не в среде f
is вызывается с .
f
определяется в глобальной среде, поэтому здесь ищется x
.
Неважно, что with
был вызван для создания новой среды, из которой вызывается f
, поскольку среда, из которой его вызывается, не участвует в поиске свободных переменных.
Чтобы заставить это работать так, как вы хотите, создайте копию f
и сбросьте ее окружение, поскольку именно это R использует для поиска свободных переменных:
with(list(x = 42), { environment(f) <- environment(); f() })
По общему признанию, это немного обременительно, но вы могли бы несколько упростить его, используя пакет proto, так как proto
сбрасывает среду каждой функции, которая явно вставлена в объект proto:
library(proto)
with(proto(x = 42, f = f), f())
ДОБАВЛЕНО:
Обратите внимание, что если ваша цель состоит в объектно-ориентированном программировании (согласно вашему комментарию к другому ответу), то вам может потребоваться заглянуть в прото на домашней странице proto . Например, мы могли бы определить объект прото p
и переопределить f
, чтобы его метод был p
(в этом случае он должен принять объект в аргументе 1) следующим образом:
library(proto)
p <- proto(x = 42, f = function(.) print(.$x))
p$f()
ДОБАВЛЕНО 2:
В присоединенном кейсе, f()
сначала просматривает глобальную среду, так как именно здесь определено f
. Так как x
не найден в глобальной среде, он смотрит на родителя глобальной среды и в этом случае находит его там. Мы можем обнаружить родителя глобальной среды, используя parent.env
, и здесь мы видим, что присоединенная среда стала родителем глобальной среды.
> attach(list(x = 42))
> parent.env(.GlobalEnv)
<environment: 0x048dcdb4>
attr(,"name")
[1] "list(x = 42)"
Мы можем просматривать глобальную среду и всех ее предков в следующем порядке:
> search()
[1] ".GlobalEnv" "list(x = 42)" "package:stats"
[4] "package:graphics" "package:grDevices" "package:utils"
[7] "package:datasets" "package:methods" "Autoloads"
[10] "package:base"
Таким образом, "list(x = 42)"
является родителем глобальной среды, stats является родителем "list(x = 42)"
и т. Д.