2
(defun highest (lat)
    (cond
        ((null lat) nil)
        ((null (cdr lat)) (car lat))
        (T (higher (car lat) (highest (cdr lat))))))

(defun higher (a1 a2)
    (cond
        ((> a1 a2) a1)
        (T a2)))

此功能按预期工作:

> (highest '(3 5 1 2 3))    
3. Trace: (HIGHEST '(3 5 1 2 3))
4. Trace: (HIGHEST '(5 1 2 3))
5. Trace: (HIGHEST '(1 2 3))
6. Trace: (HIGHEST '(2 3))
7. Trace: (HIGHEST '(3))
7. Trace: HIGHEST ==> 3    
6. Trace: HIGHEST ==> 3
5. Trace: HIGHEST ==> 3
4. Trace: HIGHEST ==> 5    
3. Trace: HIGHEST ==> 5

但是,如果我将参数更改为&rest

(defun highest (&rest args)
    (cond
        ((null args) nil)
        ((null (cdr args)) (car args))
        (T (higher (car args) (highest (cdr args))))))

它的行为不一样。

> (highest 3 5 1 2 3)
3. Trace: (HIGHEST '3 '5 '1 '2 '3)
4. Trace: (HIGHEST '(5 1 2 3))
4. Trace: HIGHEST ==> (5 1 2 3)
*** - >: (5 1 2 3) is not a real number

编辑:对不起,我忘了提到在第二种情况下我将参数传递给原子。我编辑了问题以使其更清楚。

4

2 回答 2

5

在调用(最高 3 2 10)之前尝试评估(跟踪最高)。然后你会看到第二个调用看起来像这样: (highest '(2 10)) 然后 &rest 参数看到一个对象,它恰好是一个列表。

要更正此问题,请使用 APPLY。APPLY 类似于​​ funcall,但它的最后一个参数必须是一个列表,并且被视为“拼接到”函数调用上。像这样:(应用#'highest(cdr args))

于 2013-04-02T22:25:17.703 回答
3

&rest表单收集作为列表本身传递的所有其余参数。在 的情况下highest (&rest args)args实际上是一个带有元素的列表,一个列表。也就是说,在调用中,args值为((3 2 10))

highestwith修饰符的第二个版本&rest总是进入条件的第二个测试,args就像一个只有一个元素的列表(恰好是一个列表)。您返回 的第一个元素args,即列表本身,(3 2 10)

两种构造的不同之处在于,在第一个版本中,您将列表作为参数传递,函数接收列表作为函数的唯一参数。在 的情况下&rest,所有参数(在这种情况下只有一个)被收集到一个列表中(在这种情况下只有一个元素)。

编辑:根据您的编辑,正如托马斯在他的评论中所说,使用&rest意味着您必须使用apply递归调用。这是正确的实现:

(defun highest (&rest args)
    (cond
        ((null args) nil)
        ((null (cdr args)) (car args))
        (T (higher (car args) (apply #'highest (cdr args))))))

(注意apply最后一行的)。

于 2013-04-02T22:11:48.037 回答