вернуть функцию внутрь с помощью блока () - PullRequest
5 голосов
/ 06 марта 2020

Как работает return() в блоке with()? Вот тестовая функция

test_func <- function(df, y) {
  with(df,
       if(x > 10){
         message('Inside step 1')
         return(1)
       }
  )
  message("After step 1")

  if(y > 10){
    message('In side step 2')
    return(2)
  }  
  message("After step 2")
}
  • Функция продолжает работать после return(1).
df <- data.frame(x = 11)
y <- 11
test_func(df, y)  ## result is 2

Выход

Inside step 1
After step 1
In side step 2
[1] 2
  • return(1) не возвращается к test_func(), а не выходит из блока with()
df <- data.frame(x = 11)
y <- 5
test_func(df, y) ## no result

Выход

Inside step 1
After step 1
After step 2

1 Ответ

3 голосов
/ 06 марта 2020

Я думаю, что главное здесь заключается в том, что return() предназначен для выхода из текущей области в родительскую область с определенным значением. В случае выполнения

return("hello")
# Error: no function to return from, jumping to top level

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

f <- function(x) x
f(return("hello"))
# Error in f(return("hello")) : 
#   no function to return from, jumping to top level

Так как мы фактически передаем вызов return() функции из глобальной среды, то здесь результат будет оценен и вернет ту же ошибку. Но учтите, что это не то, что делает with, вместо этого он захватывает передаваемые вами команды и повторно запускает их в новой среде. Это ближе к чему-то подобному

f <- function(x) eval(substitute(x))
f(return("hello"))
# [1] "hello"

Этот eval() создает новый уровень области видимости, от которого мы можем выйти, и поскольку мы не оцениваем параметр, передаваемый функции напрямую, мы просто запускаем те Для команд в другой среде return больше не оценивается в глобальной среде, поэтому ошибки нет. Таким образом, созданная нами функция в основном аналогична вызову

with(NULL, return("hello"))
# [1] "hello"

, который отличается от чего-то вроде

print(return("hello"))
# no function to return from, jumping to top level

, где параметр оценивается напрямую. Таким образом, различные значения return() действительно являются побочными эффектами нестандартной оценки в этом случае.

Когда return() используется внутри with(), вы не возвращаетесь из функции, которую вы вызывали with() from, но вы возвращаетесь из области, которую with() создал для вас, чтобы запустить вашу команду.

Как исправить эту конкретную проблему, уже описано в комментариях, оставленных @IceCreamToucan. Вам просто нужно переместить возврат за пределы with().

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