SETF既不终止也不报告错误
我是一个普通的Lisp初学者,遇到了这段代码:
I'm a Common Lisp beginner and came across this piece of code:
(let ((foo (list 42)))
(setf (rest foo) foo))
REPL似乎只是
什么是 FOO
?
FOO
最初是一个新列表,(42)
。在Lisp中,列表由 cons单元表示,这是可变内存块,每个块包含一个 CAR
和 CDR
插槽。
另一种打印方式是(42。NIL)
,其中 CAR
和 CDR
在圆点的两侧。也可以如下所示:
What is FOO
?
FOO
is initially a fresh list, (42)
. In Lisp, lists are represented by cons cells, blocks of mutable memory containing each a CAR
and a CDR
slot.
Another way to print it is (42 . NIL)
, where the CAR
and CDR
are on each side of the dot. This can also be pictured as follows:
car cdr
------------
| 42 | NIL |
------------
^
|
FOO
当您呼叫 SETF
和(rest foo)
place 和 foo
值,则表示您希望 cdr 单元格为 FOO
来保存值 FOO
。实际上,这种 SETF
的出现可能会宏扩展为对 RPLACD
。
When you call SETF
with the (rest foo)
place and the foo
value, you are saying that you want the cdr cell of FOO
to hold the value FOO
. In fact, this occurrence of SETF
is likely to macroexpand into a call to RPLACD
.
------------
| 42 | FOO |
------------
^
|
FOO
为什么REPL会永远循环?
REPL(打印)的 P部分尝试打印圆形结构。这是因为 SETF
的值是要评估的表单返回的值,而 SETF
的值是其第二个参数的值,即 FOO
。想象一下,您想用一个天真的算法编写一个cons单元格X:
Why does the REPL loop forever?
The "P" part of the "REPL" (print) tries to print your circular structure. This is because SETF
's value is the one being returned from the form being evaluated, and the value returned by SETF
is the value of its second argument, namely FOO
. Imagine you want to write a cons cell X with a naive algorithm:
1. PRINT "("
2. PRINT the CAR of X
3. PRINT " . "
4. PRINT the CDR of X
5. PRINT ")"
但是,对于 foo
,步骤4将打印相同的结构,递归,并且永远不会终止。
However, for foo
, step 4 will print the same structure, recursively, and will never terminate.
尝试设置 * PRINT-CIRCLE *
到T开头:
Try setting *PRINT-CIRCLE*
to T first:
(setf *print-circle* t)
现在,您的REPL应该很高兴:
And now, your REPL should be happy:
CL-USER> (let ((foo (list 42)))
(setf (rest foo) foo))
#1=(42 . #1#)
Sharpsign等于-符号 表示允许读者将表单的一部分影响到(读者)变量,例如#1 = ...
,然后再使用它,例如#1#
。这样就可以在读取或打印过程中表示数据之间的圆形交叉引用。在这里,我们可以看到变量#1#
表示cons单元格,其中 CAR
是42 CDR
本身是#1#
。
The "Sharpsign Equal-Sign" notation allows the reader to affect part of a form to a (reader) variable, like #1=...
, and reuse it afterwards, e.g. #1#
. This make it possible to represent circular cross-references between data, either during reading or printing. Here, we can see that the variable #1#
denotes a cons-cell, where the CAR
is 42 and the CDR
is #1#
itself.