我刚刚开始使用Lisp(Common-Lisp),这是一个计算数字列表平均值的函数
CL-USER> (defun average (list) (/ (apply #'+ list) (length list)))
AVERAGE
CL-USER> (average '(1 2 3 4))
5/2
但是如果我像这样重写函数
CL-USER> (defun average (list) (/ (+ list) (length list)))
它不起作用,因为(+'(数字列表))无法计算,因此长度的争论和+中的表达式是不相容的。
有没有一种方法可以将cajoling(list)自然地作为表达式进行评估+并作为数据传递给长度?而不是使用申请#'
我试过这个:
(defun average (list) (/ (+ list) (length '(list))))
但这似乎也没有!
答案 0 :(得分:5)
请参阅Common lisp: How many argument can a function take?
最好使用(reduce #'+ list)
代替(apply #'+ list)
,因为apply
受该函数可以采用的参数个数限制。
所以你的平均功能应该是这样的:
(defun average (list)
(/ (reduce #'+ list)
(length list)))
BTW,代码(length '(list))
返回1,因为它返回包含符号“列表”的列表的长度。
答案 1 :(得分:4)
没有理由不使用APPLY
或更好的REDUCE
。这里REDUCE
是正确的功能。
如果你在Lisp中编程,大多数时候你必须使用一个符号,命名你的操作,然后是参数。这是Lisp中的一般基本表达式。您可能期望有更短的方法来编写诸如使用函数减少列表之类的东西。但是,在基本的Lisp中没有。
(+ (list 1 2 3 4))
是一个错误,因为+
需要数字,而不是列表。
如果要对列表中的所有数字求和,则必须使用REDUCE
。此操作也称为折叠。
汇总列表中的数字:
(reduce #'+ (list 1 2 3 4))
另一种简单的方法是使用LOOP
:
(loop for n in (list 1 2 3 4) sum n)
写(length '(list))
之类的内容毫无意义,因为你引用列表。引用列表被视为数据而不是代码。由于它是常量数据,因此结果始终为1
。
获得短程序的Lisp方法之一是构建可重用函数的词汇表。一个不使用最短的符号,而是使用明显的名称创建可重用的函数。因此,如果我们求和,我们会写一个sum
函数:
(defun sum (list)
(reduce #'+ list))
然后average
是:
(defun average (list)
(/ (sum list) (length list)))