Как сократить список логических значений в Common Lisp?
-
13-10-2019 - |
Вопрос
Учитывая список значений, я хочу уменьшить список до 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?
Решение
#'and
недействителен, потому что and
макрос, а не функция.
Вы можете обойтись, чтобы определить именованную функцию, используя лямбду:
(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
ФУНКЦИЯ принимает имя функции или лямбда-выражение и возвращает соответствующий функциональный объект.
И определяется здесь: http://www.lispworks.com/documentation/HyperSpec/Body/m_and.htm
Он говорит об этом И является макросом, а не функцией.Следствием этого является то, что (FUNCTION AND) не работает, поскольку для возврата соответствующего объекта FUNCTION требуется функция, а не макрос.Как описывает sepp2k в своем ответе, вы можете создать функцию с использованием LAMBDA и использовать макрос И внутри этой функции.Макросы не могут передаваться как значения и позже вызываться через FUNCALL или APPLY .Это работает только с функциями.
Это решение записывается в виде
(reduce (lambda (x y) (and x y)) (get-some-list))
ЛЯМБДА - это макрос, который расширяется (lambda (...) ...)
в (function (lambda (...) ...))
.
Итак, вышесказанное действительно:
(reduce (function (lambda (x y) (and x y))) (get-some-list))
который может быть записан как
(reduce #'(lambda (x y) (and x y)) (get-some-list))
ФУНКЦИЯ необходима, потому что Common Lisp проводит различие между пространством имен для значений и функций.REDUCE необходимо получить функцию, передаваемую в качестве аргумента по значению.Итак, нам нужно извлечь функцию из пространства имен function, что и является целью FUNCTION .Всякий раз, когда мы хотим передать объект function, нам нужно получить его из пространства имен function.
Например, в случае локальной функции:
(flet ((my-and (x y) (and x y)))
#'my-and)
LAMBDA как удобный макрос, который расширяется до (FUNCTION (LAMBDA ...)), был добавлен при разработке Common Lisp.
Вы можете использовать символ «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: нежное введение в символическое вычисление, стр. 202