r语言 - 嵌套使用call_modify



我正在尝试创建一个对函数的调用,f该函数的第一个参数是对另一个函数的调用(我选择了dbinom作为示例(。对dbinom的调用(传递给f(不包括所有参数的值,因为这些值应该在f内完成,并且完成的调用由f返回。这是我失败的最小尝试:

f <- function(a_call) {
call_modify(a_call, x=1)
}
a_call <- call2(dbinom, size=1, prob=0.5)
y <- call2(f, a_call)

y的输出为:

(function(a_call) {
call_modify(a_call, x=1)
})((function (x, size, prob, log = FALSE) 
.Call(C_dbinom, x, size, prob, log))(size = 1, prob = 0.5))

此电话将

  • 在没有任何参数的情况下调用a_call,然后;
  • 将此结果传递给f

如果我评估y,它会出错dinom因为缺少第一个参数。

我相似但相关的结构:

> call2(call2(dbinom, x=1, size=1, prob=0.5))
((function (x, size, prob, log = FALSE) 
.Call(C_dbinom, x, size, prob, log))(x = 1, size = 1, prob = 0.5))()
(function (x, size, prob, log = FALSE) 

我感觉我在这里尝试的东西"甚至没有错",嵌套调用修改最好以另一种方式完成。

似乎您尝试执行的操作由purrr::partial()更自然地处理,它填充函数的一个或多个参数:

f <- function( a_fun ) {purrr::partial( a_fun, x=1 )}
a_fun <- purrr::partial( dbinom, size=1, prob=0.5 )
y <- f(a_fun)

y(...)现在有效地dbinom( x=1, size=1, prob=0.5, ... )

y()            # 0.5
y(log=TRUE)    # -0.6931472

partial()的伟大之处在于它可以自然地与%>%管连接:

z <- partial(dbinom, size=1) %>% partial(prob=0.5) %>% partial(x=1)
z(log=TRUE)    # -0.6931472

如果我正确理解你想做什么, 那么也许这效果更好:

f <- function(a_call) {
call_modify(call_standardise(call2(ensym(a_call)),
caller_env()),
x=1)
}

您可以带或不带字符使用:

f(print)
# print(x = 1)
f("print")
# print(x = 1)
eval(f(print))
# 1

或者更多间接:

a_call <- expr(print)
eval(call2(f, a_call))
# print(x = 1)
eval(expr(f(!!a_call)))
# print(x = 1)

由于我们在这里做了一些非标准评估, 事情变得有点棘手。call_standardise需要能够找到您指定的函数, 而且很有可能会在调用f的环境中找到它, 不一定在召唤call_standardise的环境中, 在这种情况下,这将是f的执行环境。 这就是为什么在调用call_standardise时明确指定caller_env(),即使这是后者env的默认值, 因为默认参数是在函数的执行环境中计算的, 而显式参数是在调用方的环境中计算的。

下面是此问题的一个看起来很做作的示例:

f2 <- function(a_call) {
call_modify(call_standardise(call2(ensym(a_call))),
x=1)
}
e <- new.env()
e$foo <- function(x) { x + 1 }
with(e, f(foo))
# foo(x = 1)
with(e, f2(foo))
# Error in eval_bare(node_car(expr), env) : object 'foo' not found

但是,如果您要开发一个提供f的包, 该示例不再人为:f会存在于您的包的环境中, 其他包可以为仅在其各自命名空间中可用的函数调用它。

有关更多细节和描述, 检查此参考, 也许尝试为我的示例绘制调用树。

call2通过将计算...参数传递给可调用对象(第一个参数(来构造调用。例如,以下命令输出到控制台"y",因为计算传递给call2的第二个参数,

> A <- call2(print, x=print('y'))
[1] "y"

并构造一个对print的调用,该调用以x="y"作为其参数(而不是x=print("y")(:

> A
(function (x, ...) 
UseMethod("print"))(x = "y")

为了绕过a_call被评估然后在构造调用中传递(f(,可以引用它,例如

f <- function(a_call) {
call_modify(a_call, x=1)
}
a_call <- call2(dbinom, size=1, prob=0.5)
y <- call2(f, quote(a_call))

现在:

> y
(function(a_call) {
call_modify(a_call, x=1)
})(a_call)

最新更新