有条件地修改父函数

时间:2017-09-09 15:45:15

标签: r function namespaces call evaluation

背景

我有兴趣将一个对象返回到父函数框架并停止执行父函数而不会出现错误。

备注

我在SO上进行了一些讨论on related questions,并同意更广泛的观点,即这不一定是最佳实践。我最感兴趣的是这样做是为了教育目的,并更好地理解如何使用function call stack

可重复的示例

check_conditions

此函数应检查条件,并在某些特定情况下将结果返回到父函数。

check_conditions <- function(x) {
    stopifnot(is.numeric(x),
              x %% 1 == 0)
    # And for x == 9 always return 9
    if (x == 9) {
        eval.parent(return(1))
        stop()
    }
}

其他功能

其余的函数使用check_conditions函数并稍后执行自己的操作(如果已停止,则执行自己的操作)。

fun_a <- function(x) {
    check_conditions(x)
    x^2
}

fun_b <- function(x) {
    check_conditions(x)
    x+1
}

问题

>> fun_b(1)
[1] 2

>> fun_a(9)
[1] 81

>> fun_b(9)
[1] 10

在上面的示例中,我希望fun_afun_b根据条件返回值 1

if (x == 9) {
            eval.parent(return(1))
            stop()
        }

注释

  • 我不想返回错误消息。 应该没有消息,表示未处理fun_afun_b之间的剩余调用。

更新(根据评论)

  • 我不想更改fun_afun_b的正文,check_conditions可以更改。
  • 应该可以更改假设fun_n的行为,该行为也会引用​​check_conditions 而不编辑该功能。 check_conditions应该能够返回并停止(没有错误或警告)并在函数的父环境中返回值, R-ish 伪代码

    check_conditions <- function(x) {
    if (x == 9) {
       call(env = parent.frame(),
            expr = {
                    return(1)
                    # Do not execute anything else from 
                    # the parent environment.
            }
      }
     }
    

1 个答案:

答案 0 :(得分:1)

这是从旧答案修改而来的。它不需要更改check_conditionsfun_a,但需要:

  • fun_a通过fun_a <- validity_check(fun_a)之类的电话进行注册,然后fun_a可以使用
  • check_conditions的调用必须是正文的第一行
  • check_conditions采用与fun_a
  • 相同的参数

代码:

validity_check <- function(fun) {
   cl <- body(fun)[[2]][[1]]
   function(...) {
     mc <- match.call()
     mc[[1]] <- cl
     check_val <- eval.parent(mc)
     if (!is.null(check_val)) check_val
     else fun(...) 
   }
}

# test - fun_a and check_conditions as in question

fun_a <- validity_check(fun_a)

fun_a(9)
## [1] 1

fun_a(2)
## [1] 4

陈旧回答我不清楚可以改变什么,什么不可以但是如果我们可以修改所有功能那么:

check_conditions <- function(x) {
    stopifnot(is.numeric(x), x %% 1 == 0)
    if (x == 9) structure(1, class = "bad")
}

fun_a <- function(x) {
  cc <- check_conditions(x)
  if (inherits(cc, "bad")) unclass(cc) else x^2
}

fun_a(9)
## [1] 1

fun_a(2)
## [1] 4