【问题标题】:promise already under evaluation: recursive default argument reference or earlier problems?承诺已经在评估中:递归默认参数引用或早期问题?
【发布时间】:2011-05-20 10:00:23
【问题描述】:

这是我的 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 &lt;- function(g.=g, T=1, f..=f){ g.(1,T, f.=f..) } 的东西吗?在有更多递归的情况下,添加更多 . 是否是一种安全且安全的做法?

(2) 如果f 是一个非函数参数,例如g &lt;- function(x, T, f=f){ exp(-f*x/T) }test &lt;- function(g.=g, T=1, f=f){ g.(1,T, f=f.) },将对正式和实际的非函数参数使用相同的名称是一种安全的好做法,否则可能会导致一些潜在的麻烦?

【问题讨论】:

    标签: r


    【解决方案1】:

    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) 如果函数 test 进一步接受 f 的参数,你会添加类似 test?在有更多递归的情况下,添加更多 . 是否是一种安全且安全的做法? (2) 如果 f 是非函数参数,例如 g x/T) }* 和 test 将使用相同的名称正式和实际的非功能性参数是一种良好且安全的做法,否则可能会导致一些潜在的麻烦?
    • 还有其他解决方案吗?我在函数链的深处(大约 5 个级别)传递了一些参数,这个解决方案可以变成.....cumbersome。 :)
    • @RomanLuštrik 如果您要向下传递参数并且可以安全地忽略其中一些参数,请考虑使用省略号 ... 或列表将参数向下传递函数链。它比预先定义所有内容要灵活得多(无论好坏)。您可能最终需要添加一些检查以确保省略号(或列表)中的原始参数是合理的。
    • 这里的另一个选项是显式尝试在父框架中查找参数,绕过主动承诺的意外强制——例如get("f", envir = parent.frame()).
    • 唯一的要求是不要在左右两边使用相同的名字。除此之外,它只是风格。
    【解决方案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】:

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

    【讨论】:

      【解决方案4】:

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

      这不起作用:

      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 &lt;- function(x = x){},但你可以使用my.function(x = x) 调用函数。当你定义函数时,R 会感到困惑,因为它发现参数 x =x 的本地值,但是当你调用函数时,R 会在你调用的本地环境中找到 x = 4

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

      【讨论】:

        猜你喜欢
        • 2013-06-23
        • 1970-01-01
        • 1970-01-01
        • 2021-06-30
        • 2017-09-20
        • 1970-01-01
        • 2018-07-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多