这是我的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)
}
运行错误是:
&GT;试验()
test()出错:
承诺已经在评估中:递归默认参数引用还是早期问题?
如果我将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.) }
,则对于正式和实际非函数参数使用相同的名称安全的做法还是可能会造成一些潜在的麻烦?
答案 0 :(得分:131)
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
答案 1 :(得分:6)
如上所述,问题出在将函数参数定义为自身。但是,我想添加一个为什么的解释,这是一个问题,因为理解使我找到了一种更简单的方式(对我来说)避免该问题:只需在调用中指定参数而不是定义
这不起作用:
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感到困惑,因为R会找到参数x =
作为x
的局部值,但是当您调用函数R时会在本地环境中找到x = 4
来自。
因此,除了通过更改参数名称或显式指定环境(如其他答案中所述)来修复错误外,您还可以在调用函数时(而不是在定义函数时)指定x=x
。对我来说,在调用中指定x=x
是最好的解决方案,因为它不涉及额外的语法,也不涉及越来越多的变量名。
答案 2 :(得分:2)
如果您指定参数评估上下文,则可以避免同名问题:
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
答案 3 :(得分:0)
我喜欢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