我正在使用父函数通过返回父函数调用中的函数来生成子函数.父函数的目的是在子函数中设置常量(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)
Run Code Online (Sandbox Code Playgroud)
如果检查R函数的类型,您将观察到以下内容:
> typeof(square)
[1] "closure"
Run Code Online (Sandbox Code Playgroud)
那就是,其实完全回答你的问题:一个封闭是围绕承载环境的功能.
R还告诉你这是哪个环境(尽管不是非常有用):
> square
function(x){return(x^y)}
<environment: 0x7ffd9218e578>
Run Code Online (Sandbox Code Playgroud)
(确切的数字会因每次运行而有所不同 - 它只是一个内存地址.)
现在,这对应于哪个环境?它对应于我们执行时创建的本地环境power(2)(" 堆栈帧 ").正如另一个答案所说,它现在是square函数的父环境(事实上,在R中,每个函数,除了某些内部函数,都与父环境相关联):
> ls(environment(square))
[1] "y"
> environment(square)$y
[1] 2
Run Code Online (Sandbox Code Playgroud)
您可以在Hadley的Advanced R书中的章节中阅读有关环境的更多信息.
顺便提一下,闭包是函数式编程语言的核心特性.函数式语言的另一个核心特性是每个表达式都是一个值 - 而且,通过暗示,函数的(返回)值是其最后一个表达式的值.这意味着使用returnR中的函数既不必要又具有误导性!1因此,您应该将其删除:这会产生更短,更易读的代码:
power = function (y) {
function (x) x ^ y
}
Run Code Online (Sandbox Code Playgroud)
这里还有另一个特定的R细节:因为参数是懒惰地评估的,所以你的函数定义容易出错:
> two = 2
> square = power(two)
> two = 10
> square(5)
[1] 9765625
Run Code Online (Sandbox Code Playgroud)
哎呀!变量的后续修改two反映在内部square(但仅在第一次!进一步的重新定义不会改变任何东西).为防止这种情况,请使用以下force功能:
power = function (y) {
force(y)
function (x) x ^ y
}
Run Code Online (Sandbox Code Playgroud)
force 只需强制评估参数名称,仅此而已.
1误导,因为它return是R中的一个函数,与程序语言相比具有略微不同的含义:它中止当前的函数exectuion.