(lexical-let ((x 1))
(lambda (x y)
(+ x y)))
扩展出来的结果是
(lambda
(&rest --cl-rest--)
(apply
'(lambda
(#:G535 x y)
(+
(symbol-value #:G535)
y))
'#:--x-- --cl-rest--))
谁能帮忙解释一下这个结果的意思?完全看不懂阿
(lexical-let ((x 1))
(lambda (x y)
(+ x y)))
扩展出来的结果是
(lambda
(&rest --cl-rest--)
(apply
'(lambda
(#:G535 x y)
(+
(symbol-value #:G535)
y))
'#:--x-- --cl-rest--))
谁能帮忙解释一下这个结果的意思?完全看不懂阿
感觉就是把原来 x
的位置换成一个类似于全局变量的东西。
简单的说这个根编译器有关。跟first order logic里scope的概念一个意思。
#:--x--
绑定的是未扩展前的表达式中的 x
的值 1。生成的表达式中的 x
没有作用。另外,#:--x--
应该是个 uninterned symbol,你用的 Common Lisp ?
elisp也有uninterned symbol啊. 把print-gensym设置为t就会输出这种格式了.
我觉得比较奇怪的是
就是把 (x 1)
放到全局作用域,所以需要一个唯一的“索引”。
在我这里:
(macroexpand
'(lexical-let ((x 1))
(lambda (x y)
(+ x y))))
展开之后是这样的:
(let ((--cl-x-- (make-symbol "--x--")))
(setf (symbol-value --cl-x--) 1)
(list (quote lambda)
(quote (&rest --cl-rest--))
(list (quote apply)
(list (quote quote)
(function (lambda (G42 x y)
(+ (symbol-value G42) y))))
(list (quote quote) --cl-x--) ;; (x 1) 的那个 x, 对应 lambda 参数 G42
(quote --cl-rest--)))) ;; lambda 其余的参数
我也不明白 lambda 的 x 参数的用意,最后不是没用到吗?
以前似乎有印象 CL 会在 print uninterned symbol 的时候前面加上 #:
,并不知道 elisp 也这样。
因为 lexical scope,所以不管外面传什么 x
,也是不影响的。为了模拟 lexical scope 的效果,展开时你需要隐式传入一个新的参数(即保存 lexical scope 里那个 x
的值的 symbol),原来函数接受 2 个参数,所以就变成 3 个了。然后 partially apply,又变回两个,外面看上去没有变化。
#:G535
是一个 uninterned symbol,看 @twlz0ne 贴的展开形式会更清楚,作用就是用来代替原来的 x
symbol。既然 x
原来是个 symbol,所以也得传进来一个 symbol,取值就用 symbol-value
了。
这么看来的话,lexical-let的实现是有bug的。 就以这个例子来说,很显然(+ x y) 中的x是指代lambda中的参数x,而扩展后变成指向lexical-let中的x了。
可以试着去 http://emacs.stackexchange.com/ 去提问,的确 lexical-let
和开启 lexical-binding
的 let
是不一样的。(也许本来就不一样?或者是 bug ?)