13

给定一个值列表,如果所有元素都不是 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

为什么“#'and”无效?在 Common Lisp 中有没有更惯用的方法来做到这一点?

4

3 回答 3

21

您可以使用 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(函数与)也是如此。

功能在这里描述: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)

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

于 2010-12-26T21:01:35.597 回答
10

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

您可以通过使用 lambda 来避免必须定义命名函数:

(reduce (lambda (x y) (and x y)) (get-some-list) :initial-value t)

虽然没有捷径#'

或者,您也可以使用everyidentify 函数作为谓词。

于 2010-12-26T20:21:23.673 回答
3

您只能将“尖引号”符号用于普通函数。

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:符号计算的简单介绍,第 202 页

于 2010-12-26T20:28:19.233 回答