我不明白为什么Emacs 24的新词法作用域功能如此之好的原因是我想不出任何没有它们就无法实现的新功能。例如,以下闭包:
(setq lexical-binding t)
(defun f1 (num1)
(lambda (num2)
(setq num1 (* num1 num2))))
(fset 'f2 (f1 5))
==> (closure ((num1 . 5) t) (num2) (setq num1 (* num1 num2)))
(f2 5)
==> 25
(f2 2)
==> 50
可以使用常规动态范围实现,如下所示:
(defun f1 (num)
(let ((tmpvar (make-symbol "num")))
(set tmpvar num)
`(lambda (num2)
(set ',tmpvar (* (eval ,tmpvar) num2)))))
(fset 'f2 (f1 5))
==> (lambda (num2) (set (quote num) (+ (eval num) num2)))
(f2 5)
==> 25
(f2 2)
==> 50
(fset 'f3 (f1 9))
==> (lambda (num2) (set (quote num) (+ (eval num) num2)))
(f3 3)
==> 27
(f3 2)
==> 54
(f2 10)
==> 500
好吧,所以并非所有的语言都有类似于elisp的uninterned符号的东西,所以我理解为什么词法范围在他们的情况下如此之大。但是elisp怎么样?你能想到我现在可以做的任何事情(就像Emacs 24一样),这是我以前做不到的,这要归功于词法范围吗?
答案 0 :(得分:5)
您不需要未加工的符号,使用cons
代替make-symbol
,car
代替eval
,setcar
代替set
并且你的例子也会起作用(并且效率更高)。
另请注意,从机器语言到更高级语言的发展主要基于使越来越多的事情不可能(或者至少更难)。当然,那些远离程序员的设施很少被使用和/或被认为太危险。考虑使用未初始化的变量(可能在C中,但在Java和许多其他语言中是不可能的),或者跳到指令的中间。
至于你的示例代码的一些缺点:不仅它的可读性较差,而且编译器基本上无法知道你正在构造代码,因此不允许在里面查看“`( lambda ...)“编译它,扩展它的宏调用,给你关于可疑元素的警告,......
答案 1 :(得分:4)
在Emacs中总是有模拟词法绑定的解决方法,所以它不是能够做新事物。
手册说:
词法绑定为优化提供了更多机会,所以 使用词法绑定的Emacs Lisp代码可能会运行 在未来的Emacs版本中更快。这样的代码也更加友好 并发性,我们希望在不久的将来添加到Emacs。
我认为这是主要的好处。
另一方面,当Emacs出于正当理由而有目的地选择动态绑定时,今天仍然如此,因此词汇绑定当然不应被视为新的做事方式。
全局变量在编程中通常被认为是一个坏主意,但Emacs是一个不常见的情况,因为它的大部分灵活性 - 使Emacs很棒的关键因素之一 - 直接来源于动态绑定。如果没有动态绑定,就不可能将应用程序弯曲到单个用户的要求,而不是像Emacs允许的那样。
在我看来,词法绑定应该谨慎使用,并且只适用于其他用户无法想象的覆盖变量的变量。默认情况下,变量应为defvar
'd,以便保留自定义行为的能力(即使是作者未预料到的方式)。
答案 2 :(得分:0)
我认为面向对象编程的实现往往与词法范围很吻合。具有状态映射的对象而不是直接到词法闭包。
我确信常见的lisp中的CLOS实现会大量利用词法范围。我很难想象如何仅使用动态范围来实现该规范,但我确信它是可能的。