另请注意,结合
- 词法作用域的概念(我们觉得这对编程语言来说是一件好事,而不是动态作用域)
- 函数定义(lambda 表达式)深深嵌入代码中(也可以简称为“嵌套函数”)
从语言实现的角度和程序员的角度来看,这可能是一项复杂的工作。这个复杂的东西甚至还有一个特殊的名字:闭包。
正如维基百科所写:
在具有一流嵌套函数
的语言中正确实现静态作用域并非易事,因为它要求每个函数值都带有它所依赖的变量值的记录(函数和这个环境的对被称为一个闭包)。
这不仅在具有全局和/或可变变量(如 C 或 Java)的语言中实现并非微不足道;考虑在评估对在该位置范围内的可变状态的闭包时确保正确访问嵌套函数定义!只有一件事:当你在未来某个时间评估闭包时,使用的对象不应该被破坏和垃圾收集),但从概念上来说,程序员思考如何关闭将在复杂的情况下工作以及它将确切具有哪些(副作用)效果(出于相同的原因:您需要考虑闭包与定义闭包时范围内的所有可变状态的交互,例如:当您在闭包内部引用时定义到范围内的外部可变变量,您是否真的想访问变量在定义闭包时所具有的值,即您想要拥有该变量的只读副本,或者您想要在未来评估闭包时全面访问变量的可变状态?)。
在纯函数式语言中,考虑嵌套函数定义及其用途要简单得多,因此只有词法范围对它们来说根本不是问题。但是,如果您的语言不能正常工作,那么它就不是那么微不足道了。(我相信这是长期以来一直争论如何向 Java 添加闭包的原因之一:尽管它们只是建立在词法作用域的好概念之上,但它们似乎并不容易让程序员理解.)
使用动态范围考虑非纯函数式语言中的嵌套函数更简单(尽管动态范围并不好:您获得的编译时检查更少,并保证程序在动态范围内的正确行为)。
所以我认为,考虑到动态范围的所有危险,如果一个人想要并且敢于这样做,那么在一种语言中使用动态范围的优势也可以是用一种简单的方式编程一些东西的可能性。
笔记
关于 Java 中(无)闭包的悠久历史(并且程序员不喜欢这个概念) ——http: //people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg04030.html:
日期:2003 年 8 月 14 日星期四 08:05:44 -0700
来自:迈克尔·瓦尼尔
主题:回复:绑定和分配(原:回复:延续)
日期:2003 年 8 月 14 日星期四 10:45:34 -0400
来自:“大卫·B·塔克”
我想,虽然我没有统计证据,但为了在匿名内部类(闭包)中引用它们而将局部变量声明为 final 的要求几乎完全未知并且在实践中未使用。
出于好奇,有谁知道为什么 Java 只允许在匿名类中引用最终变量?
戴夫
<cynic>Otherwise you'd have the equivalent of true closures,
and if you had that java would be a
*really* powerful and useful language, so they obviously couldn't do that.
</cynic>
实际上,原型实现
确实允许从内部类中引用非最终变量。用户强烈抗议,抱怨他们不想要这个!原因很有趣:为了支持这些变量,有必要对它们进行堆分配,而且(至少在那个时候)普通的 Java 程序员仍然对堆分配和垃圾收集以及所有这些东西很敏感。当看不到“new”关键字时,他们不赞成“在桌子下”执行堆分配的语言。
因此,在早期——显然——在 Java 中采用了“第三种”方法(与我在上面提到的两种方法相反):既不是“只读副本”,也不是在评估封闭(在定义闭包时)可变状态的时间,而是状态的可变副本(至少,我这样理解引用的段落;或者不,他在谈论堆分配只是参考?..然后是第二个选项。很好。第三个选项对我来说真的不明智。)。不知道他们现在如何在 Java 中实现闭包,我没有关注最近关于 Java 的新内容。