2017-09-26 20 views
2

マクロの使い方を理解しようとしています。私はこの問題を解決する他の方法があり、マクロが最良の答えかもしれないし、そうでないかもしれないことを知っていますが、ここでの技術的な問題を理解したいと思っています。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)) 

これはほとんど動作します。私はマクロに渡されたものは評価されたコードではなく、性別だけであることを知っています。しかし、ループでこれらの関数を作成しようとすると、単純に機能しません。上記のコードで...

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

これらの両方が動作します。評価がなければ、2番目のステートメントで生のcar exprを取得するので、明らかに動作しません。

何が起こっているのですか? namecl-loopの空変数である理由は、make-my-defunまでです。私はマクロやその他のリソースに関するドキュメントを読んでいますが、私はここでいくつかの基本的な洞察が不足しています。

答えて

1

cl-loopは複雑ですが、基本的にループ内のnameバインディングはcl-symbol-macroletによって行われ、バインディングを解決するコードに展開されます。 evalは、呼び出された時点でこれについて知ることができません。理由は、(1)macroexpandが引用符で囲まれたコードに下がりたくないからです。 (2)evalが周囲の字句環境を何とか継承しないようにする。 (car model-names)と書くと、グローバルにバインドされます。

あなたはすでに、私はあなたが再びそれを使用することができますね一度evalを使用:

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

しかし、実際に、マクロがコード上で動作し、彼らは通常、評価しません。

+0

これは意味があります。テンプレート機能にマクロを使用すると、マクロ機能にはあまり適していないようです。 私は 'eval'を'(macroexpand-1 ..) 'の結果に使ってしまいましたが、これよりはるかにハッキングされていました。アイデアと説明をありがとう。 –

関連する問題