Как сократить список логических значений в Common Lisp?

StackOverflow https://stackoverflow.com/questions/4535236

  •  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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top