do.call 和 curve 不能在另一个函数环境中绘制函数

Posted

技术标签:

【中文标题】do.call 和 curve 不能在另一个函数环境中绘制函数【英文标题】:do.call and curve can not plot a function inside another function environment 【发布时间】:2013-01-12 09:59:18 【问题描述】:

我遇到了一个关于 do.callcurve 的奇怪问题:

func1 <- function (m, n) 
  charac <- paste ("func2 <- function(x)", m, "*x^", n, sep = "")
  eval(parse(text = charac))
  return(func2)

func3 <- function (m, n) 
  my.func <- func1 (m, n)
  do.call("curve",list(expr = substitute(my.func)))

func1 构造 func2func3 绘制构造的 func2。 但是当我运行 func3 时,会显示以下错误:

> func3 (3, 6)
Error in curve(expr = function (x)  : 
  'expr' must be a function, or a call or an expression containing 'x'

但是,当我运行 func1 并手动绘制输出(不应用 func3)时,func2 将被绘制

my.func <- func1 (3, 6)
do.call("curve",list(expr = substitute(my.func)))

这里发生的事情让我很困惑,我不知道为什么 do.call 不能在 func3 本地环境中绘制 func2

谢谢

【问题讨论】:

【参考方案1】:

您让这变得过于复杂 - 创建 f2 时您不需要做任何特别的事情:

f1 <- function (m, n) 
  function(x) m * x ^ n

f3 <- function (m, n) 
  f2 <- f1(m, n)
  curve(f2)

f3(3, 6)

当然,这可以通过删除 f1 来更简洁:

f4 <- function (m, n) 
  f2 <- function(x) m * x ^ n
  curve(f2)

f4(3, 6)

您可以在https://github.com/hadley/devtools/wiki/Functions 找到有关 R 范围规则的更多信息(使这项工作有效)

【讨论】:

++ :(链接比答案更多)我认为问题是如何将参数传递给在另一个函数中使用 do.call 接受表达式参数的函数,但也许我过度了阅读它。阅读您的材料,我想知道问题是否可能是传递的是闭包而不是函数? @DWin 所有函数都是闭包,所以这可能不是问题。但我真的不明白你在回答中要做什么。您可能还会发现 github.com/hadley/devtools/wiki/Computing-on-the-language 很有帮助,但它仍然很粗糙。 github.com/hadley/pryr/blob/master/R/draw-tree.r 也很有用。 @hadley 是的,我把它弄复杂了,但这只是我主要代码的一个简化示例。如您所知,R 无法处理符号计算(但是有一个名为 Ryacas 的包,它是 yacas 的接口)。在我的代码中,这种方法适用于为非线性模型自动构建 Fisher 信息矩阵,而无需用户干预 @EhsanMasoudi R 确实具有广泛的符号计算能力。【参考方案2】:

不是do.call的问题,而是substitute的问题默认在全局环境下求值。 所以 你需要告诉它必须在哪个环境中进行替换。这里显然是在 func3 的本地环境中。

这应该可行:

 do.call("curve",list(expr = substitute(my.func,
                                           env = parent.frame())))

编辑感谢 Dwin

正如评论中所说,替代 env 默认为当前评估环境。那么为什么下面的代码有效?答案在substitute的帮助下

函数的正式参数或使用显式创建的 delayAssign(),promise 的表达式槽替换了 象征。如果是普通变量,则将其值代入, 除非 env 是 .GlobalEnv 在这种情况下符号保持不变。

env = parent.frame(n=1) 等价于.GlobalEnv,这就是为什么符号 (my.func) 保持不变。所以正确的答案是:

do.call("curve",list(expr = substitute(my.func,
                                               env = .GlobalEnv)))

为了测试,我打开了新的 R 会话:

func1 <- function (m, n) 
  charac <- paste ("func2 <- function(x)", m, "*x^", n, sep = "")
  eval(parse(text = charac))
  return(func2)

func3 <- function (m, n) 
  my.func <- func1 (m, n)

  do.call("curve",list(expr = substitute(my.func,env = .GlobalEnv)))

比我说的

 func3(2,6)

【讨论】:

@EhsanMasoudi 如果它有效并且您对问题感到满意,您可以通过选中左侧的框来接受它。 substitute 的帮助页面说它是在当前环境中评估的。 您能否创建一个此代码不会引发错误的上下文?我得到“找不到函数'my.curve” 不使用新代码,但是当do.call 的第一个参数是“my.curve”时会引发错误。 @DWin 哎呀......更正了!我破解了curve 函数,我忘记删除名称。谢谢你的帮助。【参考方案3】:

这行得通:

func3 <- function (m, n) 
   my.func <- func1 (m, n); print(str(my.func))
   do.call(curve, list(expr=bquote( my.func) ) )
 

【讨论】:

不过,不知道为什么这种方法有输出。 curve 应该是接受一个函数,所以我不明白你的不理解。 对不起,我不是在谈论情节,我是在谈论打印到屏幕上的乱码。 对不起。那个 print() 调用只是我确保 my.func 在那个时候确实是一个函数的方式。可以安全地忽略或删除它。【参考方案4】:

你只需要删除行:

my.func

来自 func3。

【讨论】:

这怎么可能有帮助?

以上是关于do.call 和 curve 不能在另一个函数环境中绘制函数的主要内容,如果未能解决你的问题,请参考以下文章

lapply和do.call有什么区别?

R do.call函数中的错误[关闭]

do.call(rbind, list) 用于奇数列

curve与plot的区别

为啥我不能在另一个函数中定义一个函数?

不确定 do.call() 在 R 中在做啥