Un exemple un peu plus compliqué

Dans une application de type Emacs, on souhaite écrire une macro permettant de définir une fonction interactive (c'est-à-dire, pouvant être appelée par l'utilisateur de l'application). Pour cela on souhaite rajouter à la syntaxe de defun la possibilité de préciser comment obtenir les arguments interactivement. On souhaite par exemple pouvoir écrire :

(defun-inter mail-file-to ((filename (minibuffer-read-file))
                           (to (minibuffer-read-string))
                           (signature (numeric-argument)))
  ...
  ...)

Le résultat d'un tel appel doit donner les deux effets suivants. D'abord une fonction mail-file-to doit être définie, comme si on avait écrit :

(defun mail-file-to (filename to signature)
  ...
  ...)

puis une entrée doit être définie dans la liste de propriétés du symbole mail-file-to contenant une fonction anonyme définie avec :

(setf (get 'mail-file-to 'interactive
           #'(lambda () (mail-file-to (minibuffer-read-file)
                                      (minibuffer-read-string)
                                      (numeric-argument)))))

Pour que les deux résultats soient obtenus simultanément, la macro doit en réalité générer :

(progn
  (defun mail-file-to (filename to signature)
    ...
    ...)
  (setf (get 'mail-file-to 'interactive
             #'(lambda () (mail-file-to (minibuffer-read-file)
                                        (minibuffer-read-string)
                                        (numeric-argument))))))

Voici une solution possible :

(defmacro defun-inter (name arglist &body body)
    `(progn
       (defun ,name ,(mapcar #'car arglist)
         ,@body)
       (setf (get ',name 'interactive
                  #'(lambda ()
                      (,name ,@(mapcar #'cadr arglist)))))))

Irene DURAND
2011-10-14