2017-09-26 6 views
2

J'essaie de comprendre comment utiliser une macro. Je sais qu'il existe d'autres façons de résoudre ce problème et une macro peut ou peut ne pas être la meilleure réponse, mais je veux comprendre le problème technique ici et le résoudre d'une autre manière.Impossible de définir des fonctions avec ma macro Emacs-Lisp

(setq model-names (list "goat" "alpaca" "llama")) 

(defun some-fn (model tag) 
    (message "Great news: %s %s" model tag)) 

(defmacro make-my-defun(model) 
    `(defun ,(intern (concat "my-defun-" (eval model))) (tag) 
    "Do a thing" 
    (interactive "sTag: ") 
    (some-fn ,(eval model) tag))) 

(macroexpand-1 '(make-my-defun "goat")) 
(macroexpand-1 '(make-my-defun (car model-names))) 


(cl-loop for name in model-names 
     do 
;;   (insert (format "%s" name))) 
     (make-my-defun name)) 

Cela fonctionne presque. Je comprends que les choses passées dans une macro sont juste sexprs, pas de code évalué. Cependant, lorsque j'essaie de créer ces fonctions en boucle, cela ne fonctionne tout simplement pas. Avec le code ci-dessus ...

(make-my-defun "goat") 
(make-my-defun (car model-names)) 

Ces deux méthodes fonctionnent. Sans l'eval, cela ne fonctionnerait évidemment pas, car il s'agirait d'obtenir la voiture brute expr sur la deuxième déclaration.

Alors, que se passe-t-il? Pourquoi name est une variable vide dans mon cl-loop en ce qui concerne make-my-defun? J'ai lu les docs sur les macros et plusieurs autres ressources, mais je manque un peu de compréhension fondamentale ici.

Répondre

1

cl-loop est ... compliqué, mais basiquement, la liaison name à l'intérieur de la boucle se fait via un cl-symbol-macrolet qui se développe en code qui résout la liaison. Il n'y a aucun moyen eval savoir à ce sujet au moment où il est appelé: parce que (1) vous ne voulez pas macroexpand de descendre en code entre guillemets; (2) vous ne voulez pas que eval hérite en quelque sorte de l'environnement lexical environnant. Lorsque vous écrivez (car model-names), il est globalement lié.

Vous avez déjà utilisé eval une fois, je suppose que vous pouvez l'utiliser à nouveau:

(cl-loop for name in model-names 
     do (eval `(make-my-defun ,name))) 

Mais vraiment, les macros fonctionnent sur le code, en général, ils n'évaluent pas.

+0

Cela a du sens. L'utilisation de macros pour les fonctions de gabarit semble juste un mauvais ajustement pour l'installation de macro. J'ai été capable de faire ce travail en faisant essentiellement ce que vous avez suggéré, même si j'ai fini par utiliser 'eval' sur les résultats de' (macroexpand-1 ..) 'qui était beaucoup plus un hack que ça. Merci pour les idées et l'explication. –