Question

J'ai travaillé Common Lisp pratique et comme exercice, j'ai décidé d'écrire une macro pour déterminer si un nombre est un multiple d'un autre nombre :

(defmacro multp (value factor)
`(= (rem ,value ,factor) 0))

de sorte que :(multp 40 10)est évalué à vrai tandis que(multp 40 13)ne fait pas

La question est est-ce que cette macro fuir en quelque sorte?Est-ce aussi un « bon » Lisp ?Existe-t-il déjà une fonction/macro existante que j'aurais pu utiliser ?

Était-ce utile?

La solution

Siebel donne un aperçu détaillé (pour les cas simples en tout cas) des sources possibles de fuites, et il n'y en a aucune ici.Les deux value et factor sont évalués une seule fois et dans l’ordre, et rem n'a aucun effet secondaire.

Ce n'est pas du bon Lisp, car il n'y a aucune raison d'utiliser une macro dans ce cas.Une fonction

(defun multp (value factor)
  (zerop (rem value factor)))

est identique à toutes fins pratiques.(Notez l'utilisation de zerop.Je pense que cela rend les choses plus claires dans ce cas, mais dans les cas où vous devez souligner que la valeur que vous testez peut toujours être significative si elle est autre que zéro, (= ... 0) c'est peut-être mieux)

Autres conseils

Votre macro me semble bien.Je ne sais pas ce qu'est une macro qui fuit, mais la vôtre est assez simple et ne nécessite aucun gensyme.Pour ce qui est de savoir si c'est un "bon" Lisp, ma règle générale est d'utiliser une macro uniquement lorsqu'une fonction ne suffit pas, et dans ce cas, une fonction peut être utilisée à la place de votre macro.Cependant, si cette solution fonctionne pour vous, il n'y a aucune raison de ne pas l'utiliser.

Eh bien, en principe, un utilisateur pourrait faire ceci :

(flet ((= (&rest args) nil))
  (multp 40 10))

ce qui serait évalué à NIL...sauf que ANSI CL interdit la liaison de la plupart des symboles standard, y compris CL:=, vous êtes donc du bon côté dans ce cas particulier.

En général, bien sûr, vous devez être conscient à la fois du manque de transparence référentielle (capture des identifiants à partir du contexte dans lequel la macro est développée) et du manque d'hygiène de la macro (fuite des identifiants vers le code développé).

Non, aucun symbole introduit dans la « fermeture lexicale » de la macro n'est diffusé vers l'extérieur.

Notez qu’une fuite n’est pas NÉCESSAIREMENT une mauvaise chose, même si une fuite accidentelle l’est presque toujours.Pour un projet sur lequel j'ai travaillé, j'ai trouvé qu'une macro similaire à celle-ci était utile :

(defmacro ana-and (&rest forms)
  (loop for form in (reverse forms)
        for completion = form then `(let ((it ,form))
                                      (when it
                                       ,completion))
        finally (return completion)))

Cela m'a permis d'obtenir un "court-circuit" des choses qui devaient être faites dans la séquence, avec des arguments reportés des appels précédents dans la séquence (et un échec signalé par le retour de NIL).Le contexte spécifique d'où provient ce code est destiné à un analyseur écrit à la main pour un fichier de configuration qui a une syntaxe suffisamment bricolée pour que l'écriture d'un analyseur approprié à l'aide d'un générateur d'analyseur soit plus de travail que de le faire manuellement.

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