如果在另一个函数内创建函数,那么函数常量存储在哪里?

时间:2018-06-12 15:43:25

标签: r

我正在使用父函数通过返回父函数调用中的函数来生成子函数。父函数的目的是在子函数中设置常量(y)。以下是MWE。当我尝试调试子函数时,我无法弄清楚变量存储在哪个环境中。

power=function(y){
  return(function(x){return(x^y)})
}

square=power(2)

debug(square)

square(3)

debugging in: square(3)
debug at #2: {
    return(x^y)
}

Browse[2]> x
[1] 3
Browse[2]> y
[1] 2
Browse[2]> ls()
[1] "x"
Browse[2]> find('y')
character(0)

2 个答案:

答案 0 :(得分:5)

如果检查R函数的类型,您将观察到以下内容:

> typeof(square)
[1] "closure"

事实上,这正是您问题的答案:a closure is a function that carries an environment around

R还告诉你这是哪个环境(尽管不是非常有用):

> square
function(x){return(x^y)}
<environment: 0x7ffd9218e578>

(每次运行时确切的数字会有所不同 - 它只是一个内存地址。)

现在,这对应于哪个环境?它对应于我们执行power(2)(“stack frame”)时创建的本地环境。正如另一个答案所说,它现在是square函数的父环境(实际上,在R 每个函数中,除了某些内置函数与父环境相关联):

> ls(environment(square))
[1] "y"
> environment(square)$y
[1] 2

您可以在Hadley’s Advanced R book

章节中阅读有关环境的更多信息

顺便说一句,闭包是函数式编程语言的核心功能。函数式语言的另一个核心特性是每个表达式都是一个值 - 并且暗示,函数的(返回)值是其最后一个表达式的值。这意味着在R中使用return函数既不必要又具有误导性! 1 因此,您应该将其删除:这会产生更短,更易读的代码:

power = function (y) {
  function (x) x ^ y
}

这里还有另一个特定的R细节:因为参数是懒惰的,所以你的函数定义容易出错:

> two = 2
> square = power(two)
> two = 10
> square(5)
[1] 9765625

糟糕!变量two的后续修改反映在square内(但仅限第一次!进一步的重新定义不会改变任何内容)。为防止这种情况发生,请使用force function

power = function (y) {
  force(y)
  function (x) x ^ y
}

force只是强制评估参数名称,仅此而已。

1 误导,因为return是R中的函数并且与过程语言相比具有略微不同的含义:它中止目前的职能部门。

答案 1 :(得分:3)

变量y存储在函数的父环境中。 environment()函数返回当前环境,我们使用parent.env()来获取特定环境的父环境。

ls(envir=parent.env(environment())) #when using the browser

find()函数在这种情况下似乎没有帮助,因为它似乎只搜索已附加到全局搜索路径(search())的对象。它不会尝试解析当前范围中的变量名称。