SETF 既不终止也不报告错误
SETF neither terminates nor reports an error
我是 Common Lisp 初学者,遇到了这段代码:
(let ((foo (list 42)))
(setf (rest foo) foo))
REPL 在尝试执行时似乎永远循环。
什么是 FOO
?
FOO
最初是一个新列表,(42)
。在 Lisp 中,列表由 cons cells 表示,可变内存块包含每个 CAR
和 CDR
槽。
另一种打印方式是 (42 . NIL)
,其中 CAR
和 CDR
位于点的两侧。这也可以如下图:
car cdr
------------
| 42 | NIL |
------------
^
|
FOO
当您调用 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 cell X:
1. PRINT "("
2. PRINT the CAR of X
3. PRINT " . "
4. PRINT the CDR of X
5. PRINT ")"
但是,对于 foo
,第 4 步将递归打印相同的结构,并且永远不会终止。
你能做什么?
首先尝试将 *PRINT-CIRCLE*
设置为 T:
(setf *print-circle* t)
现在,您的 REPL 应该很高兴:
CL-USER> (let ((foo (list 42)))
(setf (rest foo) foo))
#1=(42 . #1#)
"Sharpsign Equal-Sign" 表示法允许 reader 将表单的一部分影响到 (reader) 变量,如 #1=...
,然后再使用它,例如#1#
。这使得在读取或打印期间表示数据之间的循环交叉引用成为可能。在这里,我们可以看到变量 #1#
表示一个 cons-cell,其中 CAR
是 42 而 CDR
是 #1#
本身。
我是 Common Lisp 初学者,遇到了这段代码:
(let ((foo (list 42)))
(setf (rest foo) foo))
REPL 在尝试执行时似乎永远循环。
什么是 FOO
?
FOO
最初是一个新列表,(42)
。在 Lisp 中,列表由 cons cells 表示,可变内存块包含每个 CAR
和 CDR
槽。
另一种打印方式是 (42 . NIL)
,其中 CAR
和 CDR
位于点的两侧。这也可以如下图:
car cdr
------------
| 42 | NIL |
------------
^
|
FOO
当您调用 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 cell X:
1. PRINT "("
2. PRINT the CAR of X
3. PRINT " . "
4. PRINT the CDR of X
5. PRINT ")"
但是,对于 foo
,第 4 步将递归打印相同的结构,并且永远不会终止。
你能做什么?
首先尝试将 *PRINT-CIRCLE*
设置为 T:
(setf *print-circle* t)
现在,您的 REPL 应该很高兴:
CL-USER> (let ((foo (list 42)))
(setf (rest foo) foo))
#1=(42 . #1#)
"Sharpsign Equal-Sign" 表示法允许 reader 将表单的一部分影响到 (reader) 变量,如 #1=...
,然后再使用它,例如#1#
。这使得在读取或打印期间表示数据之间的循环交叉引用成为可能。在这里,我们可以看到变量 #1#
表示一个 cons-cell,其中 CAR
是 42 而 CDR
是 #1#
本身。