使用未评估的参数创建未评估的函数调用

时间:2014-03-13 18:09:12

标签: r call eval lazy-evaluation

如果我们直接在R中调用函数,则会进行惰性求值,因此在函数体中遇到函数参数之前不会对它们进行求值。这样做的结果是在函数的开头使用match.call(),比如像lm这样的模型拟合,使用未评估的函数参数捕获调用。因此,通过执行模型拟合函数,可以使用promises而不是求值参数来检索对函数的调用。这样做的缺点是必须在可以获得带有未评估参数的调用之前执行该函数。

另一方面,R' call函数可用于创建对模型拟合函数的未评估调用,但会评估指定的参数。我想要做的是创建一个对象,该对象是对函数的未评估调用,其中函数参数也未被评估。一个相当简单的例子(假装arg1 + arg2 - 部分是计算上昂贵的东西):

Foo <- function(arg1, arg2){
 mycall <- match.call()
 value <- arg1 + arg2
 list(value = value,
      call = mycall)
}

x <- 1
y <- 2

# calling Foo directly
test1 <- Foo(x,y)
test1   # the call with unevaluated arguments is now accessible, but the 
        # computations in Foo had to be performed as well.

# now via 'call'
Foocall <- call("Foo", arg1 = x, arg2 = y)
test2 <- eval(Foocall)
test2
Foocall # Foocall is an unevaluated call to Foo, but arg1 and arg2 in 
        # Foocall are no longer promises.   

我想要的是:

Foocall <- call("Foo", arg1 = x, arg2 = y, eval.dots = FALSE)

产生

 # not run 
 > Foocall
 > Foo(arg1 = x, arg2 = y)

我的问题有一个简单的解决方案吗?

1 个答案:

答案 0 :(得分:2)

通过调用quote()来包装每个提供的参数将完成您似乎要求的内容:

Foocall <- call("Foo", arg1=quote(x), arg2=quote(y))

## Check that it works
Foocall
# Foo(arg1 = x, arg2 = y)

eval(Foocall)
# $value
# [1] 3
# 
# $call
# Foo(arg1 = x, arg2 = y)

identical(Foocall, eval(Foocall)$call)
# [1] TRUE

如果您还希望能够提供未命名的参数并让它们按位置自动匹配到相关的正式参数,只需将前一个包装在match.call()的调用中:

## Note that arg1 and arg2 not explicitly mentioned anywhere in this call
match.call(Foo, call("Foo", quote(x), quote(y))) 
# Foo(arg1 = x, arg2 = y)