给定一个值列表,如果所有元素都不是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中有更惯用的方法吗?
答案 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