如何减少普通LISP中的布尔值列表?
-
13-10-2019 - |
题
给定值列表,如果所有元素不是零,我想将列表减少到t,如果不是,则零。这给了我一个错误:
(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
为什么“#”和“”无效?是否有一种更惯用的方法可以在共同的LISP中做到这一点?
解决方案
#'and
无效,因为 and
是宏,而不是函数。
您可以通过使用lambda来定义命名函数:
(reduce (lambda (x y) (and x y)) (get-some-list) :initial-value t)
没有快捷方式 #'
尽管。
或者,您也可以使用 every
以识别功能为谓词。
其他提示
您可以使用每个功能:
(every #'identity '(T T T T T)) -> T
和
(every #'identity '(T T T T NIL)) -> NIL
最有效的方法可能是使用循环:
(loop for element in '(T T T T nil) always element) -> NIL
优势是,不需要列表元素的函数调用。
#'
是一个读取宏,可以在读取表达式过程中扩展到函数。所以 #'and
IS(功能和)。
功能在这里描述: http://www.lispworks.com/documentation/hyperspec/body/s_fn.htm
函数获取函数名称或lambda表达式,并返回相应的函数对象。
并在这里定义: http://www.lispworks.com/documentation/hyperspec/body/m_and.htm
它说这是宏,而不是函数。结果是(函数和)不起作用,因为功能需要一个函数而不是宏来返回相应的功能对象。正如Sepp2k在他的答案中所描述的那样,您可以使用lambda创建一个函数,并使用宏和内部功能。宏无法作为值传递,后来通过funcall或申请调用。这仅适用于函数。
该解决方案被写成
(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))
需要函数,因为常见的LISP在值和函数的名称空间之间有所不同。减少需求将函数作为参数按值传递。因此,我们需要从功能名称空间中检索函数 - 这是函数的目的。每当我们想传递函数对象时,我们都需要从函数名称空间中获取它。
例如,在本地函数的情况下:
(flet ((my-and (x y) (and x y)))
#'my-and)
LAMBDA作为便利宏,在公共LISP的设计期间添加了扩展到功能(lambda ...))。
您只能使用普通功能使用“尖锐的引号”符号。
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.