3.12 栈 (Stacks)

Cons 对象来表示的列表,很自然地我们可以拿来实现下推栈 (pushdown stack)。这太常见了,以致于 Common Lisp 提供了两个宏给堆使用: (push x y)x 放入列表 y 的前端。而 (pop x) 则是将列表 x 的第一个元素移除,并返回这个元素。

两个函数都是由 setf 定义的。如果参数是常数或变量,很简单就可以翻译出对应的函数调用。

表达式

(push obj lst)

等同于

(setf lst (cons obj lst))

而表达式

(pop lst)

等同于

  1. (let ((x (car lst)))
  2. (setf lst (cdr lst))
  3. x)

所以,举例来说:

  1. > (setf x '(b))
  2. (B)
  3. > (push 'a x)
  4. (A B)
  5. > x
  6. (A B)
  7. > (setf y x)
  8. (A B)
  9. > (pop x)
  10. (A)
  11. > x
  12. (B)
  13. > y
  14. (A B)

以上,全都遵循上述由 setf 所给出的相等式。图 3.9 展示了这些表达式被求值后的结构。

../_images/Figure-3.9.png

图 3.9 push 及 pop 的效果

你可以使用 push 来定义一个给列表使用的互动版 reverse

  1. (defun our-reverse (lst)
  2. (let ((acc nil))
  3. (dolist (elt lst)
  4. (push elt acc))
  5. acc))

在这个版本,我们从一个空列表开始,然后把 lst 的每一个元素放入空表里。等我们完成时,lst 最后一个元素会在最前端。

pushnew 宏是 push 的变种,使用了 adjoin 而不是 cons

  1. > (let ((x '(a b)))
  2. (pushnew 'c x)
  3. (pushnew 'a x)
  4. x)
  5. (C A B)

在这里, c 被放入列表,但是 a 没有,因为它已经是列表的一个成员了。