在函数中向curve()传递表达式

9
一个同事问了我这个问题,我也为此苦恼过。
假设我想定义一个函数,它以一个表达式(比如说 x^2)作为参数,并将该参数传递给 curve()
如果我想简单地完成这个任务,我只需要运行
curve(x^2,from=0,to=3)

并且它很好地运行。

假设我尝试设置一个包装函数(假设除了绘制曲线外,我还想在包装器中做其他事情):

f <- function(g) {
    curve(g,from=0,to=3)
}

如果我传递一个函数,这个方法就可以正常工作:

f(function(x) x^2)

如果我尝试传递 x^2,当 R 尝试评估表达式时会失败:

f(x^2)
## Error in eval(expr, envir, enclos) (from #2) : object 'x' not found

我可以通过在函数内使用substitute来试图防止这种情况发生:
f0 <- function(g) {
    str(substitute(g))
    curve(substitute(g),from=0,to=3)
}
f0(x^2)
## language x^2
## Error in curve(substitute(g), from = 0, to = 3) (from #3) : 
##  'expr' must be a function, or a call or an expression containing 'x'

好的,那么这表明我可能应该尝试一下。
f <- function(g) {
    h <- as.expression(substitute(g))
    str(h)
    curve(as.expression(substitute(g)),from=0,to=3)
}
f(x^2)
##  expression(x^2)
## Error in curve(as.expression(substitute(g)), from = 0, to = 3) (from #4) : 
##  'expr' must be a function, or a call or an expression containing 'x'

就目前而言,

  • 使用curve(h,...)时会以不同的方式失败(显示“未找到函数h”)
  • 如果用as.call()代替as.expression(),结果也会以相同方式失败
  • 无论如何,curve()都不能处理表达式:

curve(expression(x^2),from=0,to=1)
## Error in curve(expression(x^2), from = 0, to = 1) : 
##   'expr' did not evaluate to an object of length 'n'

如果我尝试调试curve()以查看发生了什么,我们会得到:

sexpr <- substitute(expr)
...
if (!((is.call(sexpr) || is.expression(sexpr)) && xname %in% 
    all.vars(sexpr))) 
    stop(...)

这里的sexprsubstitute(g),它未通过xname %in% all.vars(sexpr)测试... 有什么想法如何处理这个问题吗?

1
你试过使用 do.call 吗?它似乎可以像 lmglm 等函数一样工作。 - Rich Scriven
1个回答

6

我本不想提问再回答,但是我通过更深入的探索找到了(一个?)答案——我意识到我还没有尝试过evaleval(curve(substitute(g),from=0,to=3))不起作用,但这个方法可以:

f1 <- function(g) {
     eval(substitute(curve(g,from=0,to=3)))
}
f1(x^2)

更新: @RichardScriven建议使用do.call()也可以,实际测试可行!

f2 <- function(g) {
    do.call(curve,list(substitute(g),from=0,to=3))
}
f2(x^2)

欢迎提供更多解释!


2
看起来这个功能只是为交互式(顶层)工作而设计的,所以解决方法需要构建与您在交互式环境中编写的完全相同的调用,然后再进行评估。 - baptiste
好吧,至少你没有建议 eval(parse(...)),但你危险地接近了 :-)。我同意 Richard S. 的观点,在这种情况下,do.call 是你最好的朋友。 - Carl Witthoft

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接