如何减少Common Lisp中的布尔值列表?

时间:2010-12-26 20:13:37

标签: common-lisp apply reduce

给定一个值列表,如果所有元素都不是NIL,我想将列表缩小为T,否则为NIL。这给了我一个错误:

(apply #'and (get-some-list))

就像这样:

(reduce #'and (get-some-list))

这是我提出的最好的:

[11]> (defun my-and (x y) (and x y))
MY-AND

[12]> (reduce #'my-and '(T T T T T))
T

[13]> (reduce #'my-and '(T T T T NIL))
NIL

为什么“#”和“无效?在Common Lisp中有更惯用的方法吗?

3 个答案:

答案 0 :(得分:19)

您可以使用EVERY功能:

(every #'identity '(T T T T T))  ->  T

(every #'identity '(T T T T NIL))  ->  NIL

可能最有效的方法是使用LOOP:

(loop for element in '(T T T T nil) always element)  ->  NIL

优点是不需要对列表元素进行函数调用。

#'是一个读取宏,在读取表达式时会扩展为FUNCTION。所以#'and是(功能与)。

此处描述了FUNCTION:http://www.lispworks.com/documentation/HyperSpec/Body/s_fn.htm

FUNCTION采用函数名或lambda表达式,并返回相应的函数对象。

AND在这里定义:http://www.lispworks.com/documentation/HyperSpec/Body/m_and.htm

它说AND是一个宏,而不是一个函数。结果是(FUNCTION AND)不起作用,因为FUNCTION需要一个函数而不是一个宏来返回相应的函数对象。正如sepp2k在他的回答中所描述的那样,你可以使用LAMBDA创建一个函数并在该函数中使用宏AND。宏不能作为值传递,以后可以通过FUNCALL或APPLY调用。这仅适用于函数。

此解决方案写为

(reduce (lambda (x y) (and x y)) (get-some-list))

LAMBDA是一个将(lambda (...) ...)扩展为(function (lambda (...) ...))的宏。

所以上面真的是:

(reduce (function (lambda (x y) (and x y))) (get-some-list))

可以写成

(reduce #'(lambda (x y) (and x y)) (get-some-list))

需要FUNCTION,因为Common Lisp在值和函数的命名空间之间有所区别。 REDUCE需要通过值将函数作为参数传递。所以我们需要从函数命名空间中检索函数 - 这是FUNCTION的目的。每当我们想要传递一个函数对象时,我们需要从函数名称空间中获取它。

例如,在本地函数的情况下:

(flet ((my-and (x y) (and x y)))
  #'my-and)

在Common Lisp的设计过程中添加了LAMBDA作为扩展为(FUNCTION(LAMBDA ...))的便利宏。

答案 1 :(得分:9)

#'and无效,因为and是一个宏,而不是一个函数。

您可以使用lambda:

来定义命名函数
(reduce (lambda (x y) (and x y)) (get-some-list) :initial-value t)

虽然没有像#'这样的捷径。

或者,您也可以将every与识别功能一起用作谓词。

答案 2 :(得分:3)

只能在普通函数中使用'sharp-quote'符号。

Note that only ordinary functions can be quoted with #’. It is an error to
quote a macro function or special function this way, or to quote a symbol with
#’ if that symbol does not name a function.

> #’if
Error: IF is not an ordinary function.

COMMON LISP: A Gentle Introduction to Symbolic Computation, page 202