首页 > 解决方案 > 修改函数参数中的调用

问题描述

函数如何检查和修改作为参数接收的调用的参数?

应用程序:用户将函数调用a作为参数提供给函数b,但他们忘记指定所需的参数之一a。功能如何b检测并解决问题?

在这个最小的例子中,函数a 需要两个参数:

a <- function(arg1, arg2) {
    return(arg1 + arg2)
}

函数b接受一个调用和一个参数。注释行表明我需要做什么:

b <- function(CALL, arg3) {
    # 1. check if `arg2` is missing from CALL
    # 2. if `arg2` is missing, plug `arg3` in its place
    # 3. return evaluated call
    CALL
}

预期行为:

b(CALL = a(arg1 = 1, arg2 = 2), arg3 = 3) 
> 3

b(CALL = a(arg1 = 1), arg3 = 3) 
> 4

由于用户忘记指定所需的arg2参数,第二次调用当前失败。函数如何b自动修复这个错误?

我可以利用惰性评估在a评估之前修改调用吗?我看了看,rlang::modify_call但无法弄清楚。

标签: r

解决方案


这是一种可行的方法

b <- function(CALL, arg3) {
  scall <- substitute(CALL)
  stopifnot(is.call(scall)) #check that it's a call
  lcall <- as.list(scall)
  if (!"arg2" %in% names(lcall)) {
    lcall <- c(lcall, list(arg2 = arg3))
  }
  eval.parent(as.call(lcall))
}

我们使用substitute()CALL 参数来获取未评估的版本。我们将其转换为列表,以便我们可以修改它。然后我们将另一个带有我们想要的参数名称/值的列表附加到列表中。最后,我们将列表重新转换为调用,然后在调用者的环境中而不是在函数体本身中评估该调用。

如果您想使用rlang::modify_call其他rlang功能,您可以使用

b <- function(CALL, arg3) {
  scall <- rlang::enquo(CALL)
  stopifnot(rlang::quo_is_call(scall))
  if (!"arg2" %in% names(rlang::quo_get_expr(scall))) {
    scall <- rlang::call_modify(scall, arg2=arg3)  
  }
  rlang::eval_tidy(scall, env = rlang::caller_env())
}

推荐阅读