2017-05-15 13 views
0

私が持っている:私はオペコード・コールをコンパイルすると関数定義(Clozure Common Lisp)をコンパイル中にマクロが評価されるのはなぜですか?

(defmacro assign (name value) 
    (format t "assigning ~A to ~A~%" `,name `,value)) 

(defun opcode-call (&rest args) 
    (mapcar (lambda (arg) 
      (if (stringp arg) 
       (let ((var (gensym))) 
        (assign var arg) 
        var) 
       arg)) 
      args)) 

、REPL出力:

assigning VAR to ARG 
OPCODE-CALL 

はなぜ割り当てはコンパイル時に評価されていますか?

+2

マクロは常に、コンパイルする前に展開されます。マクロ展開中に出力を印刷しないようにするには、 '(format ...)'フォームを評価する代わりに返す必要があります(前にバッククォートを入れておきます。現時点ではとにかく何か))。 – jkiiski

答えて

5

マクロは機能です。彼らは引数を使ってコードを取り、新しいコードを返します。マクロには副作用があります。

あなたのコードは、マクロ展開中に何かを副作用として出力し、NILFORMAT関数を呼び出した結果)を返します。

(defmacro assign (name value) 
    (format t "assigning ~A to ~A~%" `,name `,value)) 

それを使用する:

CL-USER 11 > (multiple-value-list (macroexpand '(assign foo bar))) 
assigning FOO to BAR  ; prints as a side effect 
(NIL T)     ; the macro expansion returns two values NIL and T 

それは、引数を引用しても意味がありません。コードはこれと同等です:

(defmacro assign (name value) 
    (format t "assigning ~A to ~A~%" name value)) 

それはまだあなたが望むものはおそらくない展開としてNIL返します。

マクロでフォームを展開してformatの呼び出しにする場合は、その呼び出しをリストとして返す必要があります。ここでは、quasiquoteを使用してテンプレートからのリストを作成し、namevalueという2つの値を入力します。

(defmacro assign (name value) 
    `(format t "assigning ~A to ~A~%" ,name ,value)) 

たぶん、あなたは名前を引用したい:コンパイルされたコードのみ拡張が含まれるように

(defmacro assign (name value) 
    `(format t "assigning ~A to ~A~%" ',name ,value)) 
関連する問題