已经在评估中的承诺: 递归缺省参数引用还是早期的问题?

这是我的 R 代码,函数定义如下:

f <- function(x, T) {
10 * sin(0.3 * x) * sin(1.3 * x ^ 2) + 0.001 * x ^ 3 + 0.2 * x + 80
}


g <- function(x, T, f=f) {
exp(-f(x) / T)
}


test <- function(g=g, T=1) {
g(1, T)
}

运行错误是:

> 测试()
测试错误() :
已经在评估中的承诺: 递归缺省参数引用还是早期的问题?

如果我将 f的定义替换为 g的定义,那么错误就消失了。

我想知道错误是什么?如果不将 f的定义替换为 g的定义,如何纠正?谢谢!


更新:

谢谢,两个问题:

(1)如果函数 test进一步接受 f的参数,您会添加类似于 test <- function(g.=g, T=1, f..=f){ g.(1,T, f.=f..) }的内容吗?在有更多递归的情况下,添加更多 .是一种好的和安全的做法吗?

(2)如果 f是一个非函数参数,例如 g <- function(x, T, f=f){ exp(-f*x/T) }test <- function(g.=g, T=1, f=f){ g.(1,T, f=f.) },在形式和实际的非函数参数中使用相同的名称是否是一个好的、安全的做法,或者可能会引起一些潜在的麻烦?

69915 次浏览

形式为 x=x的形式参数导致了这种情况。排除发生它们的两个实例,我们得到以下结果。(你不能在函数定义的形式参数中使用 x=x的原因是它首先在函数本身中查找默认参数,所以使用这个形式告诉它使用它自己作为默认参数,但它没有被定义,所以没有意义,我们得到一个错误

f <- function(x, T) {
10 * sin(0.3 * x) * sin(1.3 * x^2) + 0.001 * x^3 + 0.2 * x + 80
}


g <- function(x, T, f. = f) {  ## 1. note f.
exp(-f.(x)/T)
}
 

test<- function(g. = g, T = 1) {  ## 2. note g.
g.(1,T)
}
 

test()
## [1] 8.560335e-37

如果指定参数计算上下文,就可以避免同名问题:

f <- function(x) {
10 * sin(0.3 * x) * sin(1.3 * x ^ 2) + 0.001 * x ^ 3 + 0.2 * x + 80
}
g <- function(x, t=1, f=parent.frame()$f) {
exp(-f(x) / t)
}
test <- function(g=parent.frame()$g, t=1) {
g(1,t)
}
test()
[1] 8.560335e-37

我喜欢 G. Grothendieck的答案,但是我想知道在你的例子中,不在函数的参数中包含函数名是否更简单,像这样:

f <- function(x, T) {
10 * sin(0.3 * x) * sin(1.3 * x^2) + 0.001 * x^3 + 0.2 * x + 80
}
g <- function(x, T) {
exp(-f(x)/T)
}
test<- function(T = 1) {
g(1,T)
}
test()
## [1] 8.560335e-37

正如前面提到的,问题来自于将函数参数定义为它自己。然而,我想添加一个 为什么的解释,这是一个问题,因为理解,导致我到一个更容易(对我来说)的方式来避免问题: 只是指定参数在调用中,而不是定义。

这种做法行不通:

x = 4
my.function <- function(x = x){}
my.function() # recursive error!

但这确实有效:

x = 4
my.function <- function(x){}
my.function(x = x) # works fine!

函数参数存在于它们自己的本地环境中。

R 首先在局部环境中查找变量,然后在全局环境中查找变量。这就像在函数内部,变量可以与全局环境中的变量同名,而 R 将使用本地定义。

使函数参数定义形成它们自己的本地环境,这就是为什么可以基于其他参数值使用默认参数值的原因,如

my.function <- function(x, two.x = 2 * x){}

所以这就是为什么你不能定义一个函数为 my.function <- function(x = x){},但是你可以使用 my.function(x = x)调用这个函数。当您定义函数时,R 会感到困惑,因为它发现参数 x =x的本地值,但是当您调用函数时,R 会发现 x = 4位于您正在调用的本地环境中。

因此,除了通过更改参数名称或显式指定其他答案中提到的环境来修复错误之外,您还可以在调用函数时而不是在定义函数时指定该 x=x。对我来说,在调用中指定 x=x是最好的解决方案,因为它不涉及额外的语法或累积越来越多的变量名。