将 return 推送到父函数

Push return to parent function

有没有办法强制父函数return输出?假设我有一个 'does something' 的函数,并且在每个函数的开头想要 'check something'。如果检查失败我想 return 'something else'.

在我下面的示例中,'does something' 是对数,'check something' 表示检查变量是否为非负数,'something else' 是否为负无穷大。

weird_log <- function(x) {
  check(x)
  log(x)
}

check <- function(x) {
  if (x <= 0)
    eval.parent(parse(text = 'return(-Inf)'))
}

这个例子不起作用

weird_log(10)  # 2.302585
weird_log(-10) # NaN

一个解决方案是 return 'something else' 如果检查发现问题,则 'something else' 否则 NULL 。然后我可以在parent函数里面写一个if就搞定了

weird_log <- function(x) {
  y <- check(x)
  if (!is.null(y)) return(y)
  log(x)
}

check <- function(x) {
  if (x <= 0) {
    -Inf
  } else {
    NULL
  }
}

此解决方案仍将大部分功能保留在单独的函数中 check() 但有没有办法将所有功能都包含在其中?


在实际问题中checking函数做的不止一个比较,而且是在多个函数中使用,所以有必要单独设置。另外 'something else' return 的 check 函数取决于输入失败的条件。


更现实的例子:

weird_log <- function(input) {
  y <- check(input)
  if (!is.null(y)) return(y)
  list(log = log(input$x))
}

check <- function(input) {
  if (is.null(input$x)) {
    list(error = 'x is missing')
  } else if (!is.numeric(input$x)) {
    list(error = 'x is not numeric')
  } else if (x <= 0) {
    list(log = -Inf, warn = 'x is not positive')
  } else {
    NULL
  }
}

KISS:

weird_log <- function(x) {
  if (check(x)) return(-Inf)
  log(x)
}

check <- function(x) {
  x <= 0
}

weird_log(10)  # 2.302585
weird_log(-10) # -Inf

更常见的是你想在检查失败时抛出错误的用例:

weird_log <- function(x) {
  check(x)
  log(x)
}

check <- function(x) {
  if(x <= 0) stop("x <= 0", call. = FALSE)
}

weird_log(10)  # 2.302585
weird_log(-10) # Error: x <= 0

因为答案实际上并没有回答这里的问题是如何做你问的。

returnFromParent <- function() {
  call <- rlang::expr(return()) 
  rlang::eval_bare(call, env = parent.frame())
}

foo <- function(){
  returnFromParent()
  print("you should not see this")
}

foo()

我找到的唯一方法是使用 rlang。

这是不依赖 rlang 的 JohnCoene 解决方案的另一个版本:

returnFromParent <- function(env = parent.frame()) {
  do.call(return, list("a"), envir = env)
}

foo <- function() {
  returnFromParent()
  "b"
}

stopifnot(foo() == "a")