在R中捕获表达式作为函数体

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上看到了类似的问题,但解决方案似乎并不能解决这个问题.

Fer*_*aft 4

这是一个允许参数没有默认值的解决方案。传递参数名称也更容易,因为它们不必用引号引起来。

请检查下面代码中的注释:

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)