我想更好地了解environments,closures和frames之间的关系。我理解功能闭包包含一个环境,环境包含一个框架和一个外壳,框架包含变量,但我对它们彼此之间的交互方式有点模糊。
也许在函数调用期间发生的事情的一个例子会有帮助吗?或者可能是图表?
答案 0 :(得分:10)
更新 R-lang将environment
定义为具有框架。我倾向于将帧视为堆栈帧,而不是从名称到值的映射 - 但是当然有data.frame
将列名称映射到向量(然后是一些...... )。我认为大多数混淆来自于原始S语言(仍然是S-Plus)没有环境对象这一事实,因此所有“框架”基本上都是环境对象现在,除了它们只能作为一部分存在调用堆栈。
例如,在S-Plus中,sys.nframe
的文档说“sys.nframe返回所有帧列表中当前帧的数字索引。” ...那个对我来说听起来很像堆栈帧...你可以在这里阅读更多关于堆栈帧的信息:http://en.wikipedia.org/wiki/Call_stack#Structure
我扩展了下面的一些解释并且始终使用术语“堆栈框架”(我希望)。
END UPDATE
我会这样解释:
环境是将变量名称映射到值的对象。每个映射称为绑定。该值可以是实际值或承诺。环境具有父环境(空环境除外)。当您在环境中查找符号但未找到该符号时,也会搜索父环境。
承诺是一种未经评估的表达方式,也是评估表达式的环境。当评估承诺时,它将替换为生成的值。
闭包是一个函数和定义函数的环境。像lm
这样的函数将具有stats命名空间环境,而用户定义的函数将具有全局环境 - 但是函数{在另一个函数f
中定义的{1}}将具有g
作为其环境的本地环境。
堆栈帧(或激活记录)代表调用堆栈上的条目。每个堆栈帧都有执行函数的本地环境,以及函数调用的表达式(以便g
工作)。
执行函数调用时,会创建一个本地环境,并将其父级设置为闭包的环境,参数与函数的形式参数匹配,并将这些绑定添加到本地环境(作为promises)。不匹配的形式参数被赋予函数的默认值(promises)(如果有的话)并标记为缺失。然后使用此本地环境和调用表达式创建堆栈帧。堆栈框架被推入调用堆栈,然后在此本地环境中评估函数体。
...所以正文中的所有符号都将在本地环境中查找(形式参数和局部变量),如果在父环境(封闭环境)中找不到,那么父母的父环境也是如此直到找到。
请注意,在这种情况下,父堆栈框架的环境是 NOT 。 sys.call
,parent.frame
函数获取调用堆栈上的环境 - 即调用者的环境和调用者的调用者环境等...
sys.frame
答案 1 :(得分:5)
this extended description by John Fox会解决您的问题吗?
它有漂亮的图表,但没有小马。
Fox & Weisberg book, "An R Companion to Applied Regression" (2011)中还有一个描述,从p开始。 417,或第8.9.1节。我认为上述PDF虽然较旧,但可能只是提供信息,如果不是更多(因为图表)。 F& W是一本很好的书,我a couple之前曾other useful stuff次插入{{3}}。 FWIW,我没有在“坚果壳中的R”一书中找到任何有用的见解。不过,我还没有任何钱伯斯的书。