Lisp 为什么此映射会导致我的REPL冻结?

Lisp 为什么此映射会导致我的REPL冻结?,lisp,common-lisp,Lisp,Common Lisp,在中,有人建议我可以替换此代码: (defun describe-paths (location edges) (apply (function append) (mapcar #'describe-path (cdr (assoc location edges))))) 为此: (defun describe-paths-mapcan (location edges) (mapcan #'describe-path (cdr

在中,有人建议我可以替换此代码:

(defun describe-paths (location edges)
  (apply (function append) (mapcar #'describe-path
               (cdr (assoc location edges)))))
为此:

(defun describe-paths-mapcan (location edges)
  (mapcan #'describe-path
               (cdr (assoc location edges))))
从概念上我当然理解为什么这应该有效,但事实并非如此;第二个变体冻结我的REPL,CL提示符永远不会返回。我必须重新启动SLIME。因此,我想知道mapcan没有使用
list
,而是使用
ncoc
,这是否是原因?因此,这些实际上不是功能相同的代码块

对于好奇的人,我想说:

(描述mapcan的客厅*边缘*)

其中,
*边*
是:

(defparameter *edges* '((living-room (garden west door)
             (attic upstairs ladder))
            (garden (living-room east door))
            (attic (living-room downstairs ladder))))
以及:


我认为这与描述边缘有关。其定义如下:

(defun describe-path (edge)
  `(there is a ,(caddr edge) going ,(cadr edge) from here.))
在那里我们可以
宏扩展
。。你会得到:

(macroexpand '`(there is a ,(caddr edge) going ,(cadr edge) from here.)) ; ==>
(CONS 'THERE
 (CONS 'IS
  (CONS 'A
   (CONS (CADDR EDGE) (CONS 'GOING (CONS (CADR EDGE) '(FROM HERE.)))))))
根据这项研究,混凝土是破坏性的。查看从
descripe path
返回的what的最后一个元素将与它返回的下一个元素共享结构,因此
ncoc
将形成一个无限循环

如果要将
描述边更改为以下内容,则它将起作用:

(defun describe-path (edge)
  (list 'there 'is 'a (caddr edge) 'going (cadr edge) 'from 'here.))

这是来自Lisp的土地吗?@DaoWen最初,但我正在尝试用其他方法在那本书中写例子,这样我就能更好地学习语言。这表明Quasikote功能实际上是一个宏,我不知道;因此,这是一个例子,说明了如何设计宏,以防止其他函数正确使用它!当然,反引号扩展器可以将其翻译为
(此处列出“from”)
;带引号的列表的行为w.r.t.破坏性更新是未定义的,因此这实际上取决于实现。@对于可移植代码的意愿避免使用反引号并始终使用
list
是否有意义?至少这样,所有的行为都是完全定义和定义的predictable@OpenLearner是的,要么这样,要么在
复制列表
调用中包装后引号形式。@本着我的精神,OpenLearner本可以避免在参数上变异函数,因为这些函数是为函数而设计的。
(defun describe-path (edge)
  (list 'there 'is 'a (caddr edge) 'going (cadr edge) 'from 'here.))