2016-10-04 4 views
1

私は(nameという名前の関数を作成します)define-easy-handler macro from the hunchentoot packageを学び、仕事に関数定義の一部を得たが、私はこのマクロは*observers*と呼ばれるリストに名前をプッシュすることができません。例をなぜこの共通のlispマクロは最初のs-expを評価しないのですか?

(defmacro add-observer (name params &body body) 
    ;; add NAME to the list *observers* 
    `(push ,name *observers*) 
    ;; define a lisp function with the name NAME 
    ;; with key arguments given in PARAMS 
    `(defun ,name (&key ,@(loop for p in params 
           collect p)) 
     ,@body))) 

(add-observer below-80 (id blood-sugar) 
       (when (< blood-sugar 80) 
       (format t "Patient No: ~A is hypoglycemic." id)) 

関数名が定義されていると正常に動作しますが、名前がリスト*observers*に追加されません:#'add-observerに呼んでいます。両方のs式をprognの中に入れるかどうかは関係ありません。マクロエキスパンドは、pushへの呼び出しがないことを明確に示しています。私は間違った解釈をしていますか?

EDIT

のように私はprognのでこれを試してみてください。それはUnbound variable: below-80で失敗

`(progn 
    (push ... 
    (defn ... 

。そして私がバッククォートを# 'pushと#' defunに戻すと、再び# 'pushは機能しません。

+0

'progn'を使ってうまく動作します。あなたがそれを追加するとき何を観察していますか? –

+0

@Madara Uchiha私はprognの使用に間違いを付け加えました。おそらく私は予言を悪用するでしょう。 – barerd

+1

これがあなたの本当のマクロであれば、 '(pのparams collect pは)'は単に '(copy-list params)'です。しかし、コピーはここでは不要です。 – coredump

答えて

3

マクロはソースフォームを取得し、最初の結果フォームを計算します。(push foo *observers*)このフォームはガベージコレクタのニルバナに戻されます。これはどこにも格納されず、呼び出し元には返されず、実行されません。それはすぐにごみです。だから、巧妙なコンパイラでもそれを削除する可能性があります。

マクロフォームは、(defun ...)という2番目のフォームを計算します。このフォームはマクロから返され、後で実行されます。

マクロ展開時に最初のフォームを実行する場合は、バッククォートとコンマを削除して実行可能にする必要があります。

また、生成されたソースコードに含める場合は、すべてのサブフォームを囲むprognフォームを返す必要があります。

あなたはまた、 PUSHPUSHNEW、マクロフォームが実行されます/拡張し、複数回の効果について考えたいかもしれません

...

シンボルの

不要な評価マクロ

を使用してを思い出してください:シンボルはLispコードの変数です。それらをシンボルとして扱う場合は、シンボルやデータ構造を引用する必要があります。

言って、自分のフォームは次のとおりです。

(add-observer below-80 ...) 

below-80が引用符で囲まれていないことを意味すること。

今、あなたはあまりにも、記号が引用符で囲まれていないコードを生成:

(push below-80 ...) 

当然のことながら、これはあなたのコード内で結合していないように思われ、変数below-80を評価しようとします。

below-80を評価中にシンボルにする場合は、'below-80とする必要があります。あなたの生成されたコードは次のようになります。

(push 'below-80 ...) 

を引用それあなたのコード内

(add-observer 'below-80 ...) 

または拡張へマクロことで、次のいずれか

(push 'below-80 ...) 

そのためのバッククォートテンプレートis

`(progn 
    (push ',name ...) 
    ...) 
+0

私の意図は第2のケースです。ここでprognの正しい使い方を見せてもらえますか? – barerd

+0

@barerd:展開を見る必要があります。何かを評価したくない場合は、どこかで*引用する必要があります。コード内またはマクロ展開中。 –

関連する問題