在将函数传递给其他函数之前构建函数

Jos*_*ood 8 parameters r function ellipsis

我的目标是获取通过省略号传递的附加参数...(请参阅?dots参考资料 获取更多信息),并使用已设置的参数构建一个新的通用函数,并将其传递给另一个函数。

例如,给定两个函数:

foo <- function(v, FUN, ...) {
    ## code here to build NEWFUN
    SomeFun(v, NEWFUN)
}

bar <- function(v, FUN) {
    SomeFun(v, FUN)
}
Run Code Online (Sandbox Code Playgroud)

我希望能够在以下位置执行此操作foo

bar(x, FUN = \(x) paste(x, collapse = ", "))
Run Code Online (Sandbox Code Playgroud)

通过调用foo(x, paste, collapse = ", ").

我的尝试

我们从一个简单的函数开始,它采用一个基R函数(此处paste)并将其应用于向量。请注意,我试图使其尽可能简单,因此我删除了健全性检查。另外,我写这个只是为了用基本R函数来演示paste

FunAssign <- function(f, x) f(x)
Run Code Online (Sandbox Code Playgroud)

这是我天真的尝试:

foo <- function(v, FUN, ...) {
    FUN <- \(x) FUN(x, ...)
    FunAssign(FUN, v)
}
Run Code Online (Sandbox Code Playgroud)

调用它,我们得到错误:

foo(letters[1:5], paste, collapse = ", ")
#> Error in FUN(x, ...) : unused argument (collapse = ", ")
Run Code Online (Sandbox Code Playgroud)

如上所述,调用时所需的输出可以通过如下foo(letters[1:5], paste, collapse = ", ")调用来模拟:bar

bar <- function(v, FUN) FunAssign(FUN, v)

bar(letters[1:5], FUN = \(x) paste(x, collapse = ", "))
#> [1] "a, b, c, d, e"
Run Code Online (Sandbox Code Playgroud)

我认为我的尝试foo会起作用,因为如果我们执行如下所示的操作,那么我们似乎走在正确的轨道上:

baz <- function(FUN, ...) \(x) FUN(x, ...)

baz(paste, collapse = ", ")(letters[1:5])
#> [1] "a, b, c, d, e"
Run Code Online (Sandbox Code Playgroud)

我找到了一些几乎可以满足我的要求的资源,但没有一个完全符合我的要求。

use*_*330 8

我认为如果您不覆盖FUN中的变量,您的第一个想法就会起作用foo()。也就是说,这对我有用:

FunAssign <- function(f, x) f(x)

foo <- function(v, FUN, ...) {
    force(FUN)
    FUN2 <- \(x) FUN(x, ...)
    FunAssign(FUN2, v)
}

foo(letters[1:5], paste, collapse = ", ")
Run Code Online (Sandbox Code Playgroud)

除了重命名 中的第二个FUN之外foo(),我还添加了force(FUN)命令。在本示例中这不是必需的,但一般来说,确保对创建的函数中所需的参数进行求值是一个好主意。我认为这会在这段代码中自动发生(因为FunAssign将使用它),但我对类似的事情很迷信。

编辑添加:对此的解释相当简单。

  • FUN函数中的变量在被调用FUN2()之前不会被求值FUN2()
  • FUN2被调用时FunAssign(FUN2, v),R 尝试评估FUN(x, ...)
  • 由于FUN未在该函数中定义,R 会在父环境中查找,并FUN在求值框架中找到 ,foo()作为函数调用的参数。
  • 在您的原始代码中,两个对象都名为FUN,该查找发生在您用不同的变量(我调用的函数FUN2)覆盖参数之后。
  • 当 R 尝试计算 时FUN(x, ...),在您的代码中,FUN它正在使用的是在那里定义的那个,并且 R 尝试递归调用,但会给出错误,因为该函数只有一个名为 的参数x

这里的关键是函数体只是一个未计算的表达式。在您调用该函数之前,它不会被求值,此时 R 会尝试查找它使用的所有对象,包括它调用的函数。