你还不知道 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 是五十多年前的事了,不是当时的硬件就没有什么实感。老夫都没到五十岁。
序列化,基本上所有语言都有。你这里指的是list或object转化为可打印形式,还是指其它的什么?
你的实验倒是和我昨晚留作今天要确认的问题相关
我现在正在看Practical Common lisp,每天能抽出来的时间不多,就一天一章的消化吧。好在一章内容才十几页
指的是 closure 转化为可打印形式,我的意思是打印出来的 (closure ...)
并不代表 closure 的实际结构,至少引用是丢失了的。
Common Lisp 里任何物件都有地址,closure 自然也有。打印成 ,#<TYPE ADDRESS>
是所有没有设置如何打印的物件的模式行为,只要设置 pprint dispatch 就算把 clsoure 物件打印成 "fuc*"
都可以。
为什么Capture by value 就不需要eq ?
比如:Java就是Capture by value,但它还是有 == 。
eq 有点特殊
他会认为 1 == 1 但 #xFFFFFFFFFFFFFFFF != #xFFFFFFFFFFFFFFFF
他会认为 ?c == ?c 但 “hello” != “hello”
而且 (eq '(1) '(1)) 返回的居然是nil 但是 '() == '()
(eq nil '()) ;; => t
你的试验结果正印证了我的观点:
eq一点不特殊,即:
如果比较的对象是数值,则直接比较两个数值;如果比较对象是object,则比较他们的地址。
(eq 1 1) ; => t
因为1是数值
(eq #xFFFFFFFF #xFFFFFFFF) ; => t
同理,#xFFFFFFFF是数值
(eq #xFFFFFFFFFFFFFFFF #xFFFFFFFFFFFFFFFF) ; => nil
虽然#xFFFFFFFFFFFFFFFF)是数值,但是超过了整数的最大位数32BIT,所以底层变成了一个object数据结构,于是比较的是地址
(eq "hello" "hello") ;; => nil
因为string在ELisp里被看成一个object,于是比较的是地址。
注意:这与Java的String对象很类似,只不过在Elisp里这个string不会被intern,而Java的String字面量会intern,于是Java可以直接对String字面量进行==比较,而Elisp不行。如果你想用和Java那样的intern的string,请使用(eq 'hello 'hello) ; => t
(eq '(1) '(1)) ; => nil
这是因为'(1)
是一个list,它是object,所以比较的是地址
(eq '() '()) ; => t
这是因为'()
空列表在Elisp里被看成和Java null一样的东西,显然 null == null
你错了,eq 永远比较的是地址,只是 Lisp 中为了效率实现成同样数字(整数,浮点数)通常是同个地址罢了。如果是早期用 Church encoding 表示数字的实现 eq 两个相同数值就会是 nil 了。Common Lisp 标准对 eq 两个数值没有任何保证。
==
很明显是个重载运算符,eq 不是。对于一个 capture by value,比较地址自然没有意义。至于 Emacs 的 char 为什么也能 eq,是因为 char 实际上就是个整数。
这也不能算错吧。。。我这个只是从实现层面解释(语义层确实可以把他们全部理解为引用)
但这和是否需要eq并没有关系。
比方说 这段ELisp代码:
(setq lexical-binding t)
(let ((x "1" ))
(progn
(message x)
((lambda () (setq x "2" )))
(message x)))
这里的lambda捕获的了x,我完全可以把Elisp的closure设计成和Java那样,new一个struct把x的值包到对象里面,于是就有了capture by value。
但这并不表示我这么做了之后eq就没用了,eq的使用方式和现在并没有区别。
我一开始没有看明白值捕捉是啥,看 @cireu 的以为是传值传引用顺口说了。
然而你开口就什么 Elisp 是值捕捉,eq 是数值比较。
值捕捉只要改下 lambda 宏自动把 free variable 加进 &aux arglist 就能实现了。
我也没整懂,当时学java的时候没学fp相关的。后来也没了解java的闭包是值捕捉这种太监闭包
反正无副作用下语义一样。