curve3d找不到局部函数“ fn”

时间:2018-09-12 10:43:21

标签: r scoping

我正在尝试使用curve3d包中的emdbook函数来创建另一个函数内部局部定义的函数的轮廓图,如以下最小示例所示:

library(emdbook)
testcurve3d <- function(a) {
  fn <- function(x,y) {
    x*y*a
  }
  curve3d(fn(x,y))
}

出乎意料的是,这会产生错误

> testcurve3d(2)
 Error in fn(x, y) : could not find function "fn" 

相同的想法可以与curve-package的更基本的base功能一起使用:

testcurve <- function(a) {
  fn <- function(x) {
    x*a
  }
  curve(a*x)
}
testcurve(2)

问题在于如何curve3d进行重写以使其表现出预期的效果。

3 个答案:

答案 0 :(得分:6)

您可以暂时将功能环境attach移至搜索路径以使其起作用:

testcurve3d <- function(a) {
  fn <- function(x,y) {
    x*y*a
  }
  e <- environment()
  attach(e)
  curve3d(fn(x,y))
  detach(e)
}

分析

问题来自curve3d中的这一行:

eval(expr, envir = env, enclos = parent.frame(2))

在这一点上,我们似乎有10帧深,并且fn是在parent.frame(8)中定义的。因此,您可以编辑curve3d中的行以使用该行,但是我不确定这是否可靠。也许parent.frame(sys.nframe()-2)可能更健壮,但正如?sys.parent警告说,可能发生了一些奇怪的事情:

  

严格来说,sys.parent和parent.frame是指   父解释函数。因此,内部功能(可能或可能   未设置上下文,因此可能不会出现在调用堆栈中)   不计算在内,S3方法也可以做令人惊讶的事情。

     

当心惰性评估的影响:这两个函数来看   评估时调用堆栈,而不是评估时   被称为。将调用作为函数参数传递给它们不太可能   是个好主意。

答案 1 :(得分:2)

eval-解析解决方案绕过了一些有关变量范围的担忧。与传递变量或函数名称相反,这将直接传递变量和函数的值。

library(emdbook)

testcurve3d <- function(a) {
  fn <- eval(parse(text = paste0(
    "function(x, y) {",
    "x*y*", a,
    "}"
  )))

  eval(parse(text = paste0(
    "curve3d(", deparse(fn)[3], ")"
    )))
}

testcurve3d(2)

result

答案 2 :(得分:1)

我找到了我不太喜欢的其他解决方案,但是也许可以帮到您。

您可以创建函数fn call对象的方式,并在curve3d中对其进行评估:

fn <- quote((function(x, y) {x*y*a})(x, y))
eval(call("curve3d", fn))

除了其他功能之外,还存在连续性问题,a必须在全局环境中,但是可以使用substitute来解决。

示例:

testcurve3d <- function(a) {
  fn <- substitute((function(x, y) {
                      c <- cos(a*pi*x)
                      s <- sin(a*pi*y/3)
                      return(c + s)
                      })(x, y), list(a = a))
  eval(call("curve3d", fn, zlab = "fn"))
}

par(mfrow = c(1, 2))
testcurve3d(2)
testcurve3d(5)

enter image description here