Common lisp SETF既不终止也不报告错误
我是一个普通的Lisp初学者,遇到了以下代码:Common lisp SETF既不终止也不报告错误,common-lisp,setf,Common Lisp,Setf,我是一个普通的Lisp初学者,遇到了以下代码: (let ((foo (list 42))) (setf (rest foo) foo)) 当尝试执行REPL时,它似乎一直在循环。什么是FOO? FOO最初是一个新列表,(42)。在Lisp中,列表由,个可变内存块表示,每个可变内存块包含一个CAR和一个CDR插槽。 另一种打印方法是(42.NIL),其中汽车和CDR位于点的两侧。这也可以如下所示: car cdr ------------ | 42 | NIL | ---------
(let ((foo (list 42)))
(setf (rest foo) foo))
当尝试执行REPL时,它似乎一直在循环。什么是FOO
?
FOO
最初是一个新列表,(42)
。在Lisp中,列表由,个可变内存块表示,每个可变内存块包含一个CAR
和一个CDR
插槽。
另一种打印方法是(42.NIL)
,其中汽车
和CDR
位于点的两侧。这也可以如下所示:
car cdr
------------
| 42 | NIL |
------------
^
|
FOO
当您使用(rest-foo)
位置和foo
值调用时,您的意思是希望foo
的cdr单元格保存值foo
。事实上,SETF
的出现很可能会扩展为对的调用
为什么REPL会永远循环?
“REPL”(print)的“p”部分试图打印您的循环结构。这是因为SETF
的值是从正在计算的表单返回的值,而SETF
返回的值是其第二个参数的值,即FOO
。假设您想用一个简单的算法编写一个cons单元X:
1. PRINT "("
2. PRINT the CAR of X
3. PRINT " . "
4. PRINT the CDR of X
5. PRINT ")"
但是,对于foo
,步骤4将以递归方式打印相同的结构,并且永远不会终止
你能做什么?
首先尝试设置为T:
(setf *print-circle* t)
现在,您的回复应该很高兴:
CL-USER> (let ((foo (list 42)))
(setf (rest foo) foo))
#1=(42 . #1#)
该符号允许读取器将表单的一部分影响到(读取器)变量,如\1=…
,并在以后重用它,例如\1
。这使得在读取或打印期间可以表示数据之间的循环交叉引用。在这里,我们可以看到变量#1#
表示cons单元格,其中CAR
是42,CDR
是#1#
本身。什么是FOO
?
FOO
最初是一个新列表,(42)
。在Lisp中,列表由,个可变内存块表示,每个可变内存块包含一个CAR
和一个CDR
插槽。
另一种打印方法是(42.NIL)
,其中汽车
和CDR
位于点的两侧。这也可以如下所示:
car cdr
------------
| 42 | NIL |
------------
^
|
FOO
当您使用(rest-foo)
位置和foo
值调用时,您的意思是希望foo
的cdr单元格保存值foo
。事实上,SETF
的出现很可能会扩展为对的调用
为什么REPL会永远循环?
“REPL”(print)的“p”部分试图打印您的循环结构。这是因为SETF
的值是从正在计算的表单返回的值,而SETF
返回的值是其第二个参数的值,即FOO
。假设您想用一个简单的算法编写一个cons单元X:
1. PRINT "("
2. PRINT the CAR of X
3. PRINT " . "
4. PRINT the CDR of X
5. PRINT ")"
但是,对于foo
,步骤4将以递归方式打印相同的结构,并且永远不会终止
你能做什么?
首先尝试设置为T:
(setf *print-circle* t)
现在,您的回复应该很高兴:
CL-USER> (let ((foo (list 42)))
(setf (rest foo) foo))
#1=(42 . #1#)
该符号允许读取器将表单的一部分影响到(读取器)变量,如
\1=…
,并在以后重用它,例如\1
。这使得在读取或打印期间可以表示数据之间的循环交叉引用。在这里,我们可以看到变量#1#
表示一个cons单元格,其中CAR
是42,CDR
是#1#
本身。答案很好!漂亮的回答!