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

pos*_*ist 12 reduce common-lisp apply

给定一个值列表,如果所有元素都不是NIL,我想将列表减少到T,否则就是NIL.这给了我一个错误:

(apply #'and (get-some-list))
Run Code Online (Sandbox Code Playgroud)

就像这样:

(reduce #'and (get-some-list))
Run Code Online (Sandbox Code Playgroud)

这是我提出的最好的:

[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
Run Code Online (Sandbox Code Playgroud)

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

Rai*_*wig 20

您可以使用EVERY函数:

(every #'identity '(T T T T T))  ->  T
Run Code Online (Sandbox Code Playgroud)

(every #'identity '(T T T T NIL))  ->  NIL
Run Code Online (Sandbox Code Playgroud)

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

(loop for element in '(T T T T nil) always element)  ->  NIL
Run Code Online (Sandbox Code Playgroud)

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

#'是一个读取宏,在读取表达式时会扩展为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))
Run Code Online (Sandbox Code Playgroud)

LAMBDA是一个扩展(lambda (...) ...)到 的宏(function (lambda (...) ...)).

所以上面是真的:

(reduce (function (lambda (x y) (and x y))) (get-some-list))
Run Code Online (Sandbox Code Playgroud)

可以写成

(reduce #'(lambda (x y) (and x y)) (get-some-list))
Run Code Online (Sandbox Code Playgroud)

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

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

(flet ((my-and (x y) (and x y)))
  #'my-and)
Run Code Online (Sandbox Code Playgroud)

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


sep*_*p2k 10

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

你可以通过使用lambda来定义一个命名函数:

(reduce (lambda (x y) (and x y)) (get-some-list) :initial-value t)
Run Code Online (Sandbox Code Playgroud)

虽然没有捷径#'.

或者,您也可以使用every识别函数作为谓词.