Lisp 推不工作,因为我会期待它-为什么?
我遇到了一个我没有得到的Lisp 推不工作,因为我会期待它-为什么?,lisp,common-lisp,Lisp,Common Lisp,我遇到了一个我没有得到的push函数的行为。也许有人可以向我解释为什么Lisp会这样做 假设我将列表定义为全局变量,然后尝试使用以下代码向其推送新值: (defparameter *primes* '(3 5 7 11)) (push 2 *primes*) 然后*素数*现在是(2 3 5 7 11)。到目前为止,一切顺利 现在我尝试做同样的事情,但没有*primes*变量,即: (push 2 '(3 5 7 11)) 结果是一条错误消息: EVAL:3不是函数名;尝试改用符号 现在我有两
push
函数的行为。也许有人可以向我解释为什么Lisp会这样做
假设我将列表定义为全局变量,然后尝试使用以下代码向其推送新值:
(defparameter *primes* '(3 5 7 11))
(push 2 *primes*)
然后*素数*
现在是(2 3 5 7 11)
。到目前为止,一切顺利
现在我尝试做同样的事情,但没有*primes*
变量,即:
(push 2 '(3 5 7 11))
结果是一条错误消息:
EVAL:3不是函数名;尝试改用符号
现在我有两个问题:
push
返回列表(2 3 5 7 11)
,为什么不发生这种情况?我错在哪里3告诉我的不是函数名
?当然,3
不是函数名,但我不会尝试在任何地方调用名为3
的函数,是吗非常感谢您的帮助:-)我只找到了emacs lisp手册,但我想它的行为与Common lisp类似 -宏:推送元素列表名 此宏创建一个新列表,其car为元素,其cdr为listname指定的列表,并将该列表保存在listname中 因此,
push
似乎正在修改它的参数listname
,这在文本列表中是不可能的。要做你想做的事,你可以使用cons
对于第二部分,3不是一个函数名
,我想说push
,或者它里面的某个函数,尝试计算文本列表。求值(3 5 7 11)
意味着使用参数5 7 11
调用函数3
。因此出现了错误消息
再次从emacs,Ctrl-h f push push是'cl.el'中的Lisp宏 (推X位) 在存储的列表的开头插入X。
类似于(setf位置(cons X位置)),但在 只对每个参数进行一次计算,并按正确的顺序进行计算。地点可能 可以是符号,也可以是“setf”允许的任何广义变量
setf
反过来允许place
成为
符号引用,如(car x)或(aref x i)
这解释了为什么
push
计算第二个参数。如果您阅读了的CL Hyperspec for,您将看到push
需要一个位置
位置类似于变量、结构插槽、类插槽、数组访问等。由于Lisp使用链接的cons单元格作为列表,因此在cons单元格前面推送某些内容而没有引用是没有意义的
所以上面很简单:我们不能推到直接列表。
为什么会出现此错误消息?
这有点复杂
实际上是:
(push 2 (quote (3 5 7 11))
一个函数可以是一个位置,然后它需要一个相应的setter函数。这里的setter被认为是(setf quote)
——没错,Common Lisp有时可以将列表作为函数名,而不仅仅是符号
如果我们看看上述的宏观扩张:
? (pprint (macroexpand '(push 2 (quote (3 5 7 11)))))
(LET* ((#:G328 2) (#:G327 (3 5 7 11)) (#:G326 (CONS #:G328 '#:G327)))
#:G327
#:G326
(FUNCALL #'(SETF QUOTE) #:G326 #:G327))
您可以看到它试图调用setter。但它也认为(35711)
是一种Lisp格式
我给您举一个例子,它实际上是工作的,但我们不使用quote
,而是使用一个真正的访问器函数:
CL-USER 40 > (let ((v (vector (list (list 'a 'b 'c) (list 'd 'e 'f))
(list (list 1 2 3) (list 4 5 6)))))
(print v)
(push 42 (first (aref v 1)))
(print v)
(values))
#(((A B C) (D E F)) ((1 2 3) (4 5 6)))
#(((A B C) (D E F)) ((42 1 2 3) (4 5 6)))
在上面的中,first
是getter,CL知道相应的setter。表单(arefv1)
是调用并返回向量的索引1元素。然后我们推到元素的第一个列表
您的呼叫具有类似的结构,并且
(3 5 7 11)
的位置与(aref v 1)
相似。Lisp系统表示在(3 4 7 11)
中,数字3
不是有效的函数。这是正确的。但是真正的错误是关于push
操作。由于宏无法检测到错误,因此稍后会在宏扩展代码中检测到错误。我认为第二种情况下需要CONS
:
(cons 2 '(3 5 7 11)) => (2 3 5 7 11)
CLHS
push
reference:对减号有何评论?
(cons 2 '(3 5 7 11)) => (2 3 5 7 11)