我正在尝试使用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
进行重写以使其表现出预期的效果。
答案 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)
答案 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)