call_modify 的嵌套使用
Nested use of 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)
我觉得我在这里尝试的东西 'not even wrong',嵌套调用修改最好以另一种方式完成。
如果我理解正确你想做什么,
那么也许这个效果更好:
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
会存在于您包裹的环境中,
和其他包可以调用它以获取仅在其各自命名空间中可用的功能。
有关更多细节和描述,
检查 this reference,
也许尝试为我的示例绘制调用树。
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)
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
的调用,其第一个参数是对另一个函数的调用(我选择 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)
我觉得我在这里尝试的东西 'not even wrong',嵌套调用修改最好以另一种方式完成。
如果我理解正确你想做什么, 那么也许这个效果更好:
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
会存在于您包裹的环境中,
和其他包可以调用它以获取仅在其各自命名空间中可用的功能。
有关更多细节和描述, 检查 this reference, 也许尝试为我的示例绘制调用树。
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)
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