Elisp的闭包和CommonLisp的闭包好像不太一样,现在在电车上,没法验证。先写在这里,免得明天忘了。
Elisp的闭包好像是直接把引用的值放在自己内部。而CommonLisp里是一个地址?
CommonLisp的闭包输出是这样的
(let ((count 0))
(list
#'(lambda () (incf count))
#'(lambda () (decf count))
#'(lambda () count)))
;; =>(#<CLOSURE (LAMBDA ()) {10033FCA7B}>
;; #<CLOSURE (LAMBDA ()) {10033FCA9B}>
;; #<CLOSURE (LAMBDA ()) {10033FCABB}>)
也就是,三个闭包共用同一个变量
我记得Elisp的闭包输出是这样的形式
(closure ((count . 0) t) nil (lambda () …))
这是不是,Elisp闭包的实现是把引用的变量存在自己内部一份?
上面的代码在Elisp中,三个闭包是不是共用同一个变量?哪位现在方便的话,帮我验证一下就更好了
1 个赞
有词法作用域才有闭包,所以上面代码用elisp写就不是闭包,需要使用lexical-let
我的意思是启动词法作用域,不然我上面举的例子,就不是下面这种格式了。
(closure ((count . 0) t) nil (lambda () …))
而应该是这种格式了
(lambda () …)
cireu
4
看起来是而已
(let ((a (list 1 2 3))) (setq b a fn (lambda () a)))
(cl-assert (eq (eq b (funcall fn)) t))
听起来common lisp使用了引用捕捉(capture by reference),而elisp使用了值捕捉(capture by value)
lambda的词法作用域确实有这两种实现。
比如:Java就是值捕捉。
因此,如果你想在elisp里也实现引用捕捉,方法就是用另一个对象把它包起来(i.e: Box它),这种手段在Java的lambda里也经常使用,比如用一个数组把对象包起来 [你的对象]
cireu
6
都说了看起来是,你跑跑我上面的代码就知道了,eq可是只有引用相等的时候才能返回t的。(把list换成hash-table之流也一样)
你问为啥这么诡异?要序列化的嘛
你在回复我吗?我在提醒列表里收到了Notification。。。
这鬼论坛的回复机制有问题:
只回一楼或楼上不提示,但如果一楼和楼上不是同一个人的时候,无法区分到底回复的是谁。。。
cireu
8
是回复你,紫薯补丁
三楼是回复楼主的。
我在5楼反驳你是因为你觉得Elisp是值捕获,然而人家是正版的引用捕获。
你解答错了。那一句算是我自问自答
那你3楼是回复谁的?
这论坛我真看不懂。。。
我不清楚你这个代码想描述什么?
另外还有个问题,就是:楼主说Elisp和Common Lisp的实现有区别。
这里Elisp是跑Emacs里的(Emacs本身就是运行时环境),而Common Lisp是另一个语言,应该在别的运行时环境里(Emacs只是作为编辑器)。但是ELisp又支持CL宏,这导致问题复杂化。
你让我跑这段代码,到底是要我在Emacs里跑,还是在CL的专有环境里跑?
楼主的情况也类似。
LdBeth
11
不是,你大概不懂啥叫序列化。
我之前做了点实验
说明一个闭包打印/序列化成 (closure ...)
是损失了额外的信息的。
LdBeth
12
你还不知道 Emacs 24 开始就有了 (setq lexical-binding t)
吧。
刚才测试了一下,你的这个实验在ELisp上确实没Crash。
但这并不能说明ELisp就是capture by reference,因为如果是capture by value的话,结果也是一样的。
注意:a的值实际上是list的地址,即使是capture by value,它照样获得list的地址。所以打印出来地址一样并不能说明什么。
以下证明Elisp是capture by reference
(setq lexical-binding t)
(let ((x "1" ))
(progn
(message x)
((lambda () (setq x "2" )))
(message x)))
如果是Java的话(capture by value),则对局部lambda里面的那个x修改,不会影响到外面。
1 个赞
Capture by value 就不会有 eq 这玩意了
好的,#1说明是capture by reference
到公司我就不用再验证了
歪楼请教个问题
里面的 “一只满嘴名言的牛” 有一句
A LISP programmer knows the value of everything, but the cost of nothing.
该如何理解这句话。
不知道,因为 LISP 是五十多年前的事了,不是当时的硬件就没有什么实感。老夫都没到五十岁。