1
(defun *smaller* (x y)
  ( if (> x y) y
        x))
(defun *minimum* (lst)
  (do ((numbers lst (cdr numbers))
       (result (car numbers) (*smaller* result (car numbers))))
      ((null numbers) result)))

LISP 说“最小”函数中的变量“数字”是未绑定的,尽管我认为我已将其绑定到“lst”。我错过了什么?

4

4 回答 4

4

Do并行绑定。的初始值的表达式result(cdr numbers),并且numbers在那里不受约束。 Do*会在这里工作。

于 2020-01-26T17:38:59.617 回答
2

解决这个问题的另一种方法是尝试归纳思考。

  • 空列表没有最小值;
  • 如果列表不为空,则其第一个元素是候选最小值:
    • 如果列表的其余部分为空,那就是答案
    • 否则候选最小值是当前候选和列表的第一个元素中的较小者,并继续列表的其余部分。

这很自然地转化为 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 的人(在那个时候甚至是正确的写它的名字的方式!)我认为这种归纳方法非常重要,这就是我想在这里表达的。

于 2020-01-26T20:16:20.880 回答
1

首先,如上所述,您应该使用do*而不是do, 以便按顺序绑定变量。其次,您正在测试(null numbers)结束循环。但是,当只剩下一个元素要处理时,numbers它不是 nil,而是变成(cdr numbers)了 nil。这个 nil 值是*smaller*作为第二个参数传递给的,这就是您收到错误消息的原因。为避免这种情况,您应该(null (cdr numbers))改为测试:

(defun *smaller* (x y)
  ( if (> x y) y
        x))
(defun *minimum* (lst)
  (do* ((numbers lst (cdr numbers))
       (result (car numbers) (*smaller* result (car numbers))))
      ((null (cdr numbers)) result)))

当列表中只剩下一项时,这将退出循环。

于 2020-01-27T07:46:40.310 回答
1
(defun smaller (x y)
  "returns the smaller number"
  (if (> x y)
      y
    x))

(defun minimum (list)
  "returns the smallest number of a list"
  (do* ((numbers list (rest numbers))
        (result
         (first numbers)
         (if numbers
             (smaller result (first numbers))
           result)))
       ((null numbers) result)))
于 2020-01-26T22:11:46.657 回答