当我对此感到困惑时,我在Arc教程中遇到了磕磕绊:
引自Arc Tutorial:
与Common Lisp赋值一样,Arc' s =不仅适用于变量,而且适用于变量 可以到达内部结构。所以你可以用它来修改列表:
arc> x (a b) arc> (= (car x) 'z) z arc> x (z b)
但是lisp是递归执行的,对吗?它说car
返回列表中的第一个值。所以:
arc> (car x)
a
这是有道理的,但为什么不(= (car x) 'z)
等于(= a 'z)
,这会导致:
arc> a
z
arc> x
(a b) ; Note how this hasn't changed
但它没有。相反,似乎(= (car x) 'z)
似乎具有(= x (list 'z (car (cdr x))))
:
arc> (= x '(a b))
(a b)
arc> (= (car x) 'z)
z
arc> x
(z b)
...
arc> (= x '(a b))
(a b)
arc> (= x (list 'z (car (cdr x))))
(z b)
arc> x
(z b)
那么为什么(= (car x) 'z)
确实以这种方式工作,我在这里失踪的是什么?
答案 0 :(得分:4)
=
是一个特殊的操作符,它不是一个函数。因此,它的参数不会根据正常的递归过程进行评估。第一个参数是专门处理的,它标识了要分配的位置,而不是已经存在于该位置的值。它可能必须评估其中的子表达式以找到该位置,但一旦到达该位置,它就会停止评估。第二个参数将被正常评估,以获得分配值。
答案 1 :(得分:2)
=
似乎是Arc中的赋值运算符,Common Lisp中的等价运算符为setf
。在这种情况下,(car x)
会返回要修改的地点:
? (defparameter x '(a b))
X
? x
(A B)
? (setf (car x) 'z)
Z
? x
(Z B)
另见here。
答案 2 :(得分:2)
=
是一个宏或相当"特殊运算符",它只是内置宏的一个奇特名称。宏'参数(与函数'参数不同)根本没有被评估,因此=
运算符得到(car x)
未评估==>它得到了列表(car x)
本身!现在,=
运算符包含遍历列表(car x)
的微型代码遍历器,并指出如果列表已被评估,将从哪个位置读取。并分配到那个地方。
它分配了什么?评估第二个参数的结果是,它手动评估一个参数。
因此=
的有效评估方案实际上是
(= <unevaluated-argument> <evaluated-argument>)
编辑:
宏或特殊运算符的另一个示例是if
。在(if <cond> <a> <b>)
中,if
开始首先评估并获得参数<cond>
,<a>
和<b>
raw - 未评估。然后它手动评估<cond>
并根据结果,评估<a>
或<b>
并返回结果。如果所有内容都是以递归方式进行评估的,那么您就永远无法使用if
或cond
或loop
或短路and
和or
等等......
注意:=
可能是(=我想)一个宏而不是特殊运算符,至少它在普通lisp中的等价setf
是一个宏。我怀疑P. Graham将=
直接嵌入到编译器中。但要知道它并不重要。
答案 3 :(得分:-1)
如果你有“ANSI Common Lisp”这本书,那么第3.3章就有这样的句子为什么Lisp没有指针:
理解Lisp的秘诀之一就是要意识到变量的值与列表中的元素相同。由于conses具有指向其元素的指针,因此变量具有指向其值的指针。
如果为x分配了一个列表:
arc> (= x '(a b))
(a b)
它就这样表达,变量x指向一个列表。列表的第一个位置指向符号a,第二个指向符号b:
当x的汽车在(= (car x) 'z)
中分配'z时,只需第一个位置指向新符号z。
最后,在表达式(= a 'z)
中,赋值变量a,因此指向符号z