Question

Étant donné une liste de valeurs, je veux réduire la liste à T si tous les éléments ne sont pas NIL, NIL sinon. Cela me donne une erreur:

(apply #'and (get-some-list))

Comme le fait:

(reduce #'and (get-some-list))

Ceci est le meilleur que je suis venu avec:

[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

Pourquoi "#» et" invalide? Y at-il une façon plus idiomatiques de le faire en Common Lisp?

Était-ce utile?

La solution

#'and est invalide parce and est une macro, pas une fonction.

Vous pouvez contourner avoir à définir une fonction nommée, en utilisant un lambda:

(reduce (lambda (x y) (and x y)) (get-some-list) :initial-value t)

Il n'y a pas de raccourci comme si #'.

Sinon, vous pouvez également utiliser every avec la fonction identifier comme le prédicat.

Autres conseils

Vous pouvez utiliser la fonction CHAQUE:

(every #'identity '(T T T T T))  ->  T

et

(every #'identity '(T T T T NIL))  ->  NIL

Probablement la façon la plus efficace utilise LOOP:

(loop for element in '(T T T T nil) always element)  ->  NIL

L'avantage est qu'aucun appel de fonction sur les éléments de la liste sont nécessaires.

#' est une macro de lecture qui prend son envol en FONCTION lors de la lecture de l'expression. Alors #'and est (FONCTION ET).

FONCTION est décrite ici: http://www.lispworks.com/documentation/HyperSpec/Body/ s_fn.htm

fonction prend un nom de fonction ou une expression lambda et renvoie l'objet de fonction correspondant.

est défini ici: http://www.lispworks.com/documentation/HyperSpec/Body/ m_and.htm

Il dit que ET est une macro, pas une fonction. La conséquence est que (FONCTION ET) ne fonctionne pas, puisque la fonction a besoin d'une fonction et non une macro pour renvoyer l'objet fonction correspondant. Comme sepp2k décrit dans sa réponse, vous pouvez créer une fonction à l'aide LAMBDA et utiliser la macro et à l'intérieur de cette fonction. Les macros ne peuvent être transmises sous forme de valeurs et plus tard être appelé via Funcall ou d'appliquer. Cela fonctionne uniquement avec des fonctions.

Cette solution est écrit

(reduce (lambda (x y) (and x y)) (get-some-list))

LAMBDA est une macro qui se dilate en (lambda (...) ...) (function (lambda (...) ...)).

ci-dessus est vraiment:

(reduce (function (lambda (x y) (and x y))) (get-some-list))

qui peut être écrit comme

(reduce #'(lambda (x y) (and x y)) (get-some-list))

FONCTION est nécessaire parce que Common Lisp fait une différence entre l'espace de noms pour les valeurs et les fonctions. REDUIRE besoins pour obtenir la fonction passée comme un argument en valeur. Nous avons donc besoin de récupérer la fonction de l'espace de noms de fonction - ce qui est le but de la fonction. Chaque fois que nous voulons transmettre un objet de fonction, nous devons obtenir de l'espace de noms de fonction.

Par exemple, dans le cas d'une fonction locale:

(flet ((my-and (x y) (and x y)))
  #'my-and)

LAMBDA comme macro pratique qui prend son envol en (FONCTION (LAMBDA ...)) a été ajouté lors de la conception de Common Lisp.

Vous pouvez utiliser le symbole « guillemet forte » que des fonctions ordinaires.

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: Une introduction douce au calcul symbolique, à la page 202

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top