解决这个问题的另一种方法是尝试归纳思考。
- 空列表没有最小值;
- 如果列表不为空,则其第一个元素是候选最小值:
- 如果列表的其余部分为空,那就是答案
- 否则候选最小值是当前候选和列表的第一个元素中的较小者,并继续列表的其余部分。
这很自然地转化为 Lisp:
(defun smaller (x y)
(if (< x y) x y))
(defun running-minimum (candidate tail)
(if (null tail)
candidate
(running-minimum (smaller candidate (first tail)) (rest tail))))
(defun minimum (list)
(when (null list)
(error "?")) ;ed is the standard text editor
(running-minimum (first list) (rest list)))
笔记
好的,如果现在主要是历史原因,CL 不保证这样的代码会变成一个迭代过程。许多实现都这样做,但一致的实现不需要,甚至这样做的实现也可能并不总是这样做,例如在解释代码或为便于调试而编译的代码中。所以minimum
像上面这样的函数并不是非常惯用的 CL,如果代码是可移植的,那么肯定不是完全安全的。
然而,这不是我在这个答案中的目标:在我看来,你应该从学习 lisp 中获得的重要东西之一是归纳思考解决问题的能力。换句话说,考虑一类可以通过从简单的基本情况开始,然后从一些更接近基本情况的一般情况中得到的步骤来解决的问题,然后在代码中表达出来。这是一种非常不同的编程方法,与更命令式语言中的自然方法相比,一旦你理解了它,它就是一种非常强大的思维方式。
作为第一个严肃的语言是 FORTRAN 的人(在那个时候甚至是正确的写它的名字的方式!)我认为这种归纳方法非常重要,这就是我想在这里表达的。