Динамическое перемещение управления в другое место в стеке вызовов - PullRequest
0 голосов
/ 11 января 2020

В в этом случае использования я хочу динамически переместить элемент управления в другое место в стеке вызовов. Это возможно? Ниже мы можем сделать top_level() return 2, если мы изменим return_2_from_top_level() и оставим тело top_level() в покое?

# Do not modify this:
top_level <- function() {
  return_2_from_top_level()
  Sys.sleep(2)
  1
}

# Modify this:
return_2_from_top_level <- function() {
  # What can we do here to make top_level() return 2?
  evalq(return(2), sys.frame(1)) # Does not work, but kind of shows the idea.
}

# We want 2, not 1:
top_level()
#> [1] 1

Создано в 2020-01-11 Представить пакет (v0.3.0)

Желаемый результат:

top_level()
#> [1] 2

# We still want this function body for top_level():
body(top_level)
#> {
#>     return_2_from_top_level()
#>     Sys.sleep(2)
#>     1
#> }

Ответы [ 2 ]

0 голосов
/ 12 января 2020

Как указал Г. Гротендик в своем ответе, мне пришлось изменить свою настройку. Тем не менее, я обнаружил, что пользовательские условия ошибок вполне подходили для этой цели, и результат был минимально инвазивным: https://github.com/ropensci/drake/pull/1135. Минимальный пример:

# This is what we actually call:
higher_level <- function() {
  tryCatch(
    top_level(),
    custom = function(e) {
      2
    }
  )
}

# Unmodified as promised:
top_level <- function() {
  return_2_from_top_level()
  Sys.sleep(2)
  1
}

# Modified:
return_2_from_top_level <- function() {
  stop(custom_condition())
}

custom_condition <- function() {
  structure(
    list(call = NULL, message = ""),
    class = c("custom", "error", "condition")
  )
}

higher_level()
#> [1] 2

Создано в 2020-01-11 пакетом Представить (v0.3.0)

0 голосов
/ 12 января 2020

Возможно, вы можете изменить всю настройку, чтобы избежать этого, но если нет, то можно использовать callCC.

1) Важно то, что return_2_from_top_level должен знать о g, поэтому мы сбрасываем указанные функциональные среды в значение в top, где известно g.

return_2_from_top_level <- function() g(2)

top_level <- function() { 
  return_2_from_top_level()
  Sys.sleep(2)
  1
}

top <- function(g) {
  environment(return_2_from_top_level) <- environment()
  environment(top_level) <- environment()
  top_level()   
}

callCC(top)
## [1] 2

2) В качестве альтернативы мы можем переместить определения top_level и return_2__from_top_level в top, и в этом случае явного вмешательства в окружение не будет.

top <- function(g) {

  return_2_from_top_level <- function() g(2)

  top_level <- function() { 
    return_2_from_top_level()
    Sys.sleep(2)
    1
  }

  top_level()   

}

callCC(top)
## [1] 2

3) Другая возможность - скопировать g в глобальную среду.

return_2_from_top_level <- function() g(2)

top_level <- function() { 
  return_2_from_top_level()
  Sys.sleep(2)
  1
}

top <- function(g) {
  g <<- g
  top_level()   
}

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