【问题标题】:Function can't "see" other functions defined in global environment函数不能“看到”全局环境中定义的其他函数
【发布时间】:2017-04-07 18:10:39
【问题描述】:
fa <- function(x){x+1}
fb <- function(x){x-1}

f1 <- function(x, y){f(x)^y}

f2 <- function(x, ab, y){
   if(ab == 'a'){
     f <- fa
   } else {
     f <- fb
   }
   f1(x, y)
}

f2(0, 'a', .5)
Error in f1(x, y) : could not find function "f"

上述方法不起作用,因为f 未在f1 的环境中定义。

什么是使这项工作的好方法?那个

  • 避免将全局环境中的所有内容传递给f2 的环境
  • 避免必须重新定义 f2 内的函数(这会很麻烦,并会造成复制/粘贴错误的机会)

定义某种“子全局”环境,并将我希望每个人都使用的东西放在这个环境中,然后让每个函数都能够从“子全局”访问东西是否有意义?然后以某种方式确保子全局始终是全局的严格子集?如果明智的话,我该怎么做?

【问题讨论】:

  • 一个 hacky 修复,可以让一切按原样运行,可以在调用 f1 之前在线路上使用 environment(f1) = environment() f2 因为 f1 在 @987654331 中搜索 f @。顺便说一句,全球 f1 不会受到 f2 中的此更改的影响。尽管我同意 Konrad 的观点,要么将显式函数作为参数传递,要么在方便时采用类系统。

标签: r scope s


【解决方案1】:

上述方法不起作用,因为fafb 未在f2 的环境中定义。

不——他们。错误完全不同:

f1 <- function(x, y){f(x)^y}

这里你使用了一个未定义的变量f,这是一个错误。

您在f2 中有一个不同的变量(令人困惑地也称为f)。然而,这与f1 无关,因为f1f2 不共享它们的局部变量。如果您想将f2f 传递给f1,则需要将其作为参数传递。

顺便说一句,您的变量名称非常相似这一事实使这变得比必要的复杂。如果您将代码更改为以下等效代码,问题就会变得更加清晰:

plus1 = function (x) x + 1
minus1 = function (x) x - 1

f_exp = function (x, y) g(x) ^ y

plusminus_exp = function (x, ab, y) {
    if (ab == 'a')
        f = plus1
    else
        f = minus1
    f_exp(x, y)
}

plusminus_exp(0, 'a', .5)
# Error in f_exp(x, y) : could not find function "g"

这是解决方法:

f_exp = function (x, y, g) g(x) ^ y
f_exp(x, y, f)

或者,如果您在plusminus_exp 中多次调用f_exp,您可以使用一些更高级的抽象来创建一个函数构建器:一个返回另一个函数的函数:

make_f_exp = function (f) {
    force(f)
    function (x, y)
        f(x) ^ y
}

plusminus_exp = function (x, ab, y) {
    f = if (ab == 'a') plus1 else minus1
    f_exp = make_f_exp(f)
    f_exp(x, y)
}

这使得f_exp 可插入,但隔离效果以避免引入全局可修改状态。这是函数式编程语言的标准代码,但在函数式语言之外不太常见,因此对某些人来说有点令人惊讶。

【讨论】:

  • 好吧,我的真实代码比我愚蠢的 SO 示例有更好的名称来显示我的问题。但事情是这样的:我想找到一种方法,不必将参数f 传递给f1(或者called_directly,如果你愿意的话)。我想将f 的定义设置一次,作为顶级函数的参数,然后让所有内容随后“正常工作”
  • @generic_user 这是一个错误:您打算执行的操作会创建一个mutable global state,这意味着您将在此代码的其余部分中搜索奇怪的错误。你可以做的是创建一个函数make_f1,它将一个函数作为参数并返回一个不同的函数。请参阅我的更新答案。
  • @generic_user 顺便说一句,你所说的“亚全局”环境听起来基本上像一个类。如果是这样,请查看函数式编程,尤其是 R6 系统。不过,通常应该避免这种情况,并保留在实际需要维护大型、可变、有状态对象的情况下。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-12
  • 2015-01-25
  • 1970-01-01
  • 1970-01-01
  • 2018-02-16
  • 1970-01-01
相关资源
最近更新 更多