3

マクロを書いて、次のように実行してみました。しかし、実行に失敗しました。

(defmacro times_two (var) (* 2 var))
(times_two '(+ 1 2))

私の想像では、展開は(* 2(+ 1 2))になると思います。実行後、結果は6になります。しかし失敗しました。

どうしてか分かりません。Emacs lispのマニュアルを読みましたが、それでも理解できません。拡張を構築する際の正確な手順は、いったい何であるかを知りたいです。通訳は何をしましたか?

4

2 に答える 2

7

これらのフォームを Emacs で評価すると、2 番目のフォームを評価するときに次のエラー メッセージが表示されます。

Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p (quote (+ 1 2)))
  *(2 (quote (+ 1 2)))
  (lambda (var) (* 2 var))((quote (+ 1 2)))
  (times_two (quote (+ 1 2)))
  eval((times_two (quote (+ 1 2))))
  eval-last-sexp-1(nil)
  eval-last-sexp(nil)
  call-interactively(eval-last-sexp nil nil)

これは、マクロがどのように展開されたかを示しており、何が問題だったかがわかります。(最終展開は一番上です。)

引用符で囲まれた式'(+ 1 2)は times_two マクロに渡されますが、引用符で囲まれたリストは*関数の有効な引数ではありません。

ここで実際に必要なのは次のとおりです。

(defmacro times_two (var) `(* 2 ,var))
(times_two (+ 1 2))

一般に、マクロの結果は最終的な値ではなく、新しい Lisp コードになることに注意してください。マクロを作成する目的は、必要な結果が得られるフォームを作成することです。したがって、ほとんどの場合、マクロは最終的に準引用符 (`) 構文を使用することになります。

于 2012-08-28T02:35:33.993 に答える
1

コンパイル時と実行時を混同していると思われます。マクロはコンパイル時に実行され、実行時に実行されるコードを生成します。一般的に言えば、これらをまっすぐに保つのは難しく、マクロを書くのが難しくなります。

いずれにせよ、これを ielm に入れると、次のようになります。

    ELISP> (defmacro times_two (var) 
       (* 2 var))
    times_two
    ELISP> (times_two '(+ 1 2))
    *** Eval error ***  Wrong type argument: number-or-marker-p, (quote (+ 1 2))
    ELISP> 

問題の少なくとも一部は '(+ 1 2) ですが、引用符を削除すると、次のようになります。

    ELISP> (times_two (+ 1 2))
    *** Eval error ***  Wrong type argument: number-or-marker-p, (+ 1 2)
    ELISP> 

elisp は '(+ 1 2) と (+ 1 2) を置いている場所で数字またはマーカーを探しているようです。数字を使ってみましょう:

    ELISP> (times_two 3)
    6

それはうまくいきます。

興味深いことに、これをマクロ展開すると次のようになります。

    ELISP> (macroexpand '(times_two 3))
    6

これはおそらく私たちが望んでいるものではありません。

マクロを書くときは、実行時に評価される式を返す必要があります。したがって、数値を返す代わりに、次のように試すことができます。

    ELISP> (defmacro times_two (var) 
           `(* 2 ,var))

バッククォート (quasiquote) はリストを作成する方法ですが、コンマを使用して補間することもできます。このように times_two を定義すると、次のようになります。

    ELISP> (times_two (+ 1 2))
    6

そして、次の拡張:

    ELISP> (macroexpand '(times_two (+ 1 2)))
    (* 2
       (+ 1 2))

それはまさにあなたが想像した方法です。

于 2012-08-28T18:48:44.727 に答える