你把你的括号都弄乱了:
(defun stable-union (x y)
(cond
((null x) y)
((null y) x) ) END OF COND form - has no effect
(do ((i y (cdr i))
^^
(lst3 x (append lst3
(cond
((listp i)
( (null (member (car i) lst3))
^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ called as a function
(cons (car i) nil) with two arguments
nil ) )
^^
(t NEXT 3 forms have no effect
(null (member i lst3))
(cons i nil)
nil )))) )
^^
((null (cdr i)) lst3)))
这是您可能想要的代码,带有更正的括号并if
在需要的地方添加了一些 s:
(defun stable-union (x y)
(cond
((null x) y)
((null y) x)
(t
(do ((i y (cdr i))
(lst3 x (append lst3
(cond
((listp i)
(if (null (member (car i) lst3))
(cons (car i) nil)
nil))
(t
(if (null (member i lst3))
(cons i nil)
nil))))))
((null (cdr i)) lst3)))))
这段代码仍然存在问题。你的逻辑是错误的,如果它只包含一个元素do
,它会跳过第一个元素。无论是否需要y
,您都会一直打电话。append
请注意,调用(append lst3 nil)
会复制 中的顶级 cons 单元格lst3
,这完全是多余的。
您那里的长语句通常放在正文中,而不是放在局部变量do
的更新表单中。do
do
但是您可以在适当的情况下使用更专业的 形式。这里很自然地使用dolist
. 遵循“wvxvw”关于使用哈希表进行成员资格测试的指导,我们写道:
(defun stable-union (a b &aux (z (list nil)))
(let ((h (make-hash-table))
(p z))
(dolist (i a)
(unless (gethash i h)
(setf (cdr p) (list i) p (cdr p))
(setf (gethash i h) t)))
(dolist (i b (cdr z))
(unless (gethash i h)
(setf (cdr p) (list i) p (cdr p))
(setf (gethash i h) t)))))
使用我称之为“head-sentinel”的技术(z
变量预初始化为单例列表)可以极大地简化自上而下列表构建的代码,但代价是分配一个额外的cons
单元格。