Come si fa a ridurre un elenco di valori booleani in Common Lisp?
-
13-10-2019 - |
Domanda
Dato un elenco di valori, voglio ridurre l'elenco a T se tutti gli elementi non sono NIL, NIL se non. Questo mi dà un errore:
(apply #'and (get-some-list))
Come fa questo:
(reduce #'and (get-some-list))
Questo è il migliore che è venuta in mente:
[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
Perché è "# 'e" non valido? C'è un modo più idiomatico per fare questo in Common Lisp?
Soluzione
#'and
non è valido perché and
è una macro, non una funzione.
E 'possibile andare in giro dover definire una funzione denominata, utilizzando un lambda:
(reduce (lambda (x y) (and x y)) (get-some-list) :initial-value t)
Non c'è scorciatoia come #'
però.
In alternativa si può anche utilizzare every
con la funzione di identificare come il predicato.
Altri suggerimenti
È possibile utilizzare la funzione OGNI:
(every #'identity '(T T T T T)) -> T
e
(every #'identity '(T T T T NIL)) -> NIL
Probabilmente il modo più efficiente sta usando LOOP:
(loop for element in '(T T T T nil) always element) -> NIL
Il vantaggio è che non sono necessari richiami di funzioni oltre gli elementi della lista.
#'
è una macro lettura che si espande in funzione Durante leggere l'espressione. Così #'and
è (FUNZIONE E).
funzione è descritta qui: http://www.lispworks.com/documentation/HyperSpec/Body/ s_fn.htm
accetta un nome di funzione o un'espressione lambda e restituisce l'oggetto funzione corrispondente.
ed è definito qui: http://www.lispworks.com/documentation/HyperSpec/Body/ m_and.htm
Si dice che E è una macro, non una funzione. La conseguenza è che (FUNZIONE E) non funziona, poiché la funzione necessita di una funzione e non una macro per restituire l'oggetto funzione corrispondente. Come sepp2k descrive nella sua risposta, è possibile creare una funzione tramite LAMBDA e utilizzare la macro e dentro quella funzione. Le macro non può essere passato come valori e poi essere richiamato tramite funcall o Applica. Questo funziona solo con le funzioni.
Questa soluzione è scritta come
(reduce (lambda (x y) (and x y)) (get-some-list))
LAMBDA è una macro che si espande in (lambda (...) ...)
(function (lambda (...) ...))
.
di cui sopra è in realtà:
(reduce (function (lambda (x y) (and x y))) (get-some-list))
, che può essere scritto come
(reduce #'(lambda (x y) (and x y)) (get-some-list))
è necessario FUNZIONE perché Common Lisp fa la differenza tra lo spazio dei nomi per i valori e le funzioni. RIDURRE esigenze per ottenere la funzione passata come argomento per valore. Quindi abbiamo bisogno di recuperare la funzione dalla funzione dello spazio dei nomi - che è lo scopo della funzione. Ogni volta che vogliamo passare un oggetto funzione, abbiamo bisogno di ottenere dalla funzione di spazio dei nomi.
Ad esempio nel caso di una funzione locale:
(flet ((my-and (x y) (and x y)))
#'my-and)
LAMBDA come vantaggio macro che si espande in (function (LAMBDA ...)) è stato aggiunto durante la progettazione del Common Lisp.
È possibile utilizzare il simbolo 'sharp-quote' solo con le funzioni ordinarie.
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 al calcolo simbolico, pagina 202