承诺已经在评估中:递归默认参数引用还是更早的问题?


143

这是我的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)
}

运行错误是:

> test()test()中的
错误:
承诺已在评估中:递归默认参数引用或更早的问题?

如果我将中的定义替换fg,则错误消失了。

我想知道错误是什么?如果不替代的定义,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.) },将对正式和实际的非函数参数使用相同的名称是一种好的安全做法,还是可能引起一些潜在的麻烦?

Answers:


159

形式的形式参数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

2
谢谢!两个问题(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。)},将相同的名称用于正式的和实际的非功能性参数是一种好的安全做法,否则可能会引起一些潜在的麻烦?
蒂姆(Tim)2010年

16
还有其他解决方案吗?我在功能链的很深处(大约5个级别)传递了一些参数,此解决方案可以成为.....cumbersome。:)
RomanLuštrik2012年

2
@RomanLuštrik如果要向下传递参数,并且可以放心地忽略其中的一些参数,则可以考虑使用省略号...或列表沿函数链向下传递参数。它比预定义一切要灵活得多(无论好坏)。您可能最终需要添加一些检查以确保您在省略号(或列表)中使用的原始参数是明智的。
russellpierce 2015年

2
这里的另一种选择是显式地尝试在父框架中查找参数,从而绕过主动承诺的意外强制-例如get("f", envir = parent.frame())
凯文·乌谢

1
唯一的要求是您在左侧和右侧不要使用相同的名称。除此之外,它只是样式。
G. Grothendieck

13

如果指定参数评估上下文,则可以避免出现同名问题:

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

2
我认为这是一种更好的方法,我认为指定环境会更加清晰
cloudcomputes '19

1

我喜欢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

1

如前所述,问题来自于将函数参数定义为自身。但是,我想添加一个解释为什么这是一个问题,因为理解使我找到了一种更简单的方式(对我来说)避免该问题:仅在调用中指定参数而不是定义。

这不起作用:

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在调用中指定这是最好的解决方案,因为它不涉及额外的语法或累积越来越多的变量名。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.