Как среда запоминает, что она существует? - PullRequest
3 голосов
/ 19 июня 2020

Take

adder <- local({
x <- 0
function() {x <<- x+1; x}
})

или эквивалентно

adderGen <- function(){
x <- 0
function() {x <<- x+1; x}
}
adder<-adderGen()

Вызов adder() вернет 1, повторный вызов вернет 2 и так далее. Но как это adder отсчитывает? Я не вижу никаких переменных, попадающих в глобальную среду, так что на самом деле используется для их хранения? В частности, во втором случае можно ожидать, что adder забудет, что это было сделано внутри вызова функции.

Ответы [ 2 ]

4 голосов
/ 19 июня 2020

Каждая функция сохраняет среду, в которой она была определена как часть функции. Если f - функция, то environment(f) показывает ее. Обычно среда выполнения в adderGen отбрасывается при выходе, но поскольку adderGen передает функцию, среда которой является средой выполнения в adderGen, эта среда сохраняется как часть переданной функции. Мы можем проверить это, отобразив среду выполнения в adderGen, а затем убедившись, что она такая же, как среда adder. Функция trace вставит оператор печати в начало тела adderGen и будет показывать среду выполнения при каждом запуске adderGen. environment(adder) - та же среда.

trace(adderGen, quote(print(environment())))
## [1] "adderGen"

adder <- adderGen()
## Tracing adderGen() on entry 
## <environment: 0x0000000014e77780>

environment(adder)
## <environment: 0x0000000014e77780>   
1 голос
/ 19 июня 2020

Чтобы увидеть, что происходит, давайте определим функцию следующим образом:

adderGen <- function(){
  print("Initialize")
  x <- 0
  function() {x <<- x+1; x}
}

Когда мы ее оценим, мы получим:

adder <- adderGen()
# [1] "Initialize"

Объект, который был назначен adder - это внутренняя функция adderGen (которая является выходом adderGen). Обратите внимание, что adder больше не печатает "Initialize".

adderGen
# function(){
#   print("Initialize")
#   x <- 0
#   a <- function() {x <<- x+1; x}
# }
adder
# function() {x <<- x+1; x}
# <environment: 0x55cd4ebd3390>

Мы видим, что он также создает новую вызывающую среду, которая наследует переменную x в среде adderGen .

ls(environment(adder))
# [1] "x"
get("x",environment(adder))
# [1] 0

При первом выполнении adder он использует унаследованное значение x, то есть 0, чтобы переопределить x как глобальную переменную (в своей вызывающей среде). И эта глобальная переменная будет использоваться в следующих исполнениях. Поскольку x <-0 не является частью функции adder, при выполнении adder переменная x не инициализируется значением 0 и увеличивает на единицу текущее значение x.

adder()
# [1] 1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...