Rya*_*ell 6 eval r metaprogramming substitution
我正在尝试编写一个程序,它将表达式作为输入,并返回一个函数,该表达式绑定为它的主体.
caller <- function (expr, params) {
Function <- function (params, body, env = parent.frame()) {
# returns a function
}
Function(params, body = expr)
}
func <- caller (a + b, c('a', 'b'))
func(1, 2)
[1] 3
Run Code Online (Sandbox Code Playgroud)
我可以通过使用类似的东西很容易地绑定参数
params <- c('a', 'b')
f <- function() {}
formals(f) <- structure(
replicate(length(params), NULL),
names = params
)
Run Code Online (Sandbox Code Playgroud)
我无法想出一种动态添加表达式作为正文的方法.我已经尝试过使用substitute(),并从pryr库中调整make_function,但是我无法完成任务.我最好的尝试是
body(f, parent.frame()) <- as.list( match.call() )[-1]$body
Run Code Online (Sandbox Code Playgroud)
我也无法用替代品来解决这个问题.关于如何绑定主体以使最顶层的程序按预期工作的任何想法?
我在SO上看到了类似的问题,但解决方案似乎并不能解决这个问题.
这是一个允许参数没有默认值的解决方案。传递参数名称也更容易,因为它们不必用引号引起来。
请检查下面代码中的注释:
g <- function(...)
{
# Get the arguments as unevaluated expressions:
L <- as.list(substitute(list(...)))[-1]
# The first argument is the body expression (technically a call object):
expr <- L[[1]]
# If the expression is not enclosed in curly braces, let's force it:
if( as.character(expr[[1]]) != "{" ) expr <- call("{", expr)
# Drop the first argument:
L <- L[-1]
# Mark symbols to be used as names for missing parameters:
filter <- vapply(L, is.symbol, logical(1))
params <- L
# The obscure expression "formals(function(x){})$x" returns a missing value, something really arcane ;-) :
params[filter] <- list(formals(function(x){})$x)
# Here the symbols are used as names:
names(params)[filter] <- vapply(L[filter], as.character, character(1))
# Now the result:
f <- function(){}
formals(f) <- params
body(f) <- expr
# Just to make it nicier, let's define the enclosing environment as if the function were created outside g:
environment(f) <- parent.frame()
f
}
Run Code Online (Sandbox Code Playgroud)
一些测试:
> g(a+b, a, b=1)
function (a, b = 1)
{
a + b
}
> f <- g({x <- a+b; x^2}, a, b)
> f
function (a, b)
{
x <- a + b
x^2
}
> f(2,3)
[1] 25
> f(1)
Error in a + b : 'b' is missing
> g(a+b, a=2, b=2)()
[1] 4
Run Code Online (Sandbox Code Playgroud)