GISC 练习 8.24 和 8.26:条件结果形式的条件没有按预期工作

问题描述

练习 8.24 和 8.26 David Touretzky 的“符号计算的温和介绍”状态:

8.24: 编写 COUNT-DOWN,一个使用 list-consing 递归从 n 开始倒数的函数。 (计数 5)应生成列表 (5 4 3 2 1)。

8.26:假设我们想修改 COUNT-DOWN 以便列出它 构造以零结尾。例如,(COUNT-DOWN 5) 将产生 (5 4 3 2 1 0)。 [...]

所以我尝试将这两个练习组合成一个函数 countdown,它接受​​一个关键字参数 incl-zero,如下所示:

(defun countdown (n &key (incl-zero nil))
  (cond
    ((zerop n) (if incl-zero '(0) nil))
    (t (cons n (countdown (1- n))))))

(countdown 5)
(countdown 5 :incl-zero t)

然而,两个对倒计时的调用都返回 (5 4 3 2 1),所以 :incl-zero t 似乎没有达到 if 条件。为什么会这样?

解决方法

我觉得自己很傻。

(defun countdown (n &key (incl-zero nil))
  (cond
    ((zerop n) (if incl-zero '(0) nil))
    (t (cons n (countdown (1- n) :incl-zero incl-zero)))))

(countdown 5)
(countdown 5 :incl-zero t)

我猜是递归模因的牺牲品..

,

您注意到了这个错误,但请注意,当您的参数从一次调用到另一次调用时不会改变,您可能应该定义一个局部递归函数来仅传递确实改变的参数。这更易于编写和理解。此外,传递关键字参数可能会带来一些运行时开销。

(defun countdown (n &key (incl-zero nil))
  (labels ((recurse (n)
             (cond
               ((zerop n) (if incl-zero '(0) nil))
               (t (cons n (recurse (1- n)))))))
    (recurse n)))