Управление окружающей средой функции - PullRequest
0 голосов
/ 15 января 2019

Я пытаюсь лучше понять замыкания , в частности подробности о области действия функции и о том, как работать с окружающими средами (ами)

Основываясь на разделе Description на странице справки по rlang::fn_env(), я понял, что функция всегда имеет доступ ко всем переменным в своей области и что ее окружающая среда принадлежит этой области.

Но тогда, почему невозможно манипулировать содержимым среды замыкания "по факту", то есть после создания функции?

С помощью лексической области видимости R не может ли bar() быть в состоянии найти x, когда я помещаю его в окружающую среду?

foo <- function(fun) {
  env_closure <- rlang::fn_env(fun)
  env_closure$x <- 5
  fun()
}

bar <- function(x) x

foo(bar)
#> Error in fun(): argument "x" is missing, with no default

Ответы [ 2 ]

0 голосов
/ 15 января 2019

Я действительно не могу последовать вашему примеру, так как я не знаком с библиотекой rlang, но я думаю, что хорошим примером замыкания в R будет:

bucket <- function() {
    n <- 1
    foo <- function(x) {
        assign("n", n+1, envir = parent.env(environment()))
        n
    }
    foo
}
bar <- bucket()

Поскольку bar() определено в функциональной среде bucket, то его родительской средой является bucket, и поэтому вы можете перенести туда некоторые данные. Каждый раз, когда вы запускаете его, вы изменяете среду bucket:

bar()
[1] 2
bar()
[1] 3
bar()
[1] 4
0 голосов
/ 15 января 2019

Ах, я думаю, что получил это сейчас.

Это связано со структурой формальных аргументов функции:

Если аргумент определен без значения по умолчанию, R будет жаловаться, когда вы вызываете функцию, не указывая, что она технически может найти его в своей области видимости.

Один из способов запустить лексическую область видимости, даже если вы не хотите определять значение по умолчанию, - это установить значения по умолчанию "на лету" во время выполнения с помощью rlang::fn_fmls().

foo <- function(fun) {
  env_enclosing <- rlang::fn_env(fun)
  env_enclosing$x <- 5
  fun()
}

# No argument at all -> lexical scoping takes over
baz <- function() x
foo(baz)
#> [1] 5

# Set defaults to desired values on the fly at run time of `foo()`
foo <- function(fun) {
  env_enclosing <- rlang::fn_env(fun)
  env_enclosing$x <- 5
  fmls <- rlang::fn_fmls(fun)
  fmls$x <- substitute(get("x", envir = env_enclosing, inherits = FALSE))
  rlang::fn_fmls(fun) <- fmls
  fun()
}

bar <- function(x) x
foo(bar)
#> [1] 5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...