2

letそれ自体を使用して再実装するマクロを Lisp で作成しようとしています。これは実用的な目的のない些細な演習です。しかし、関連する質問に回答した後、おそらくマクロについてもっと学ぶべきだと気づきました。これらは Lisp の優れた点の 1 つとしてもてはやされていますが、私はめったに使用しません。

とにかく、これが私が最初に試したことです:

(defmacro mylet (args &rest exp) `(let ,args (dolist (x ,exp) x)))

しかし、次のようなことを試みると:

 (mylet ((a 5) (b 2)) (print (+ a b)))

これはエラーをスローします:

  #1=(PRINT (+ A B)) is not a symbol or lambda expression in the form (#1#) .

args (a と b) は適切に設定されていますが、print ステートメントは機能しません。マクロ内で作成した変数を参照するという、2 つのレベルの間接参照を使用しているためだと思います。しかし、私はそれを修正する方法を理解できないようです!何か案は?

4

1 に答える 1

4

マクロは次のように展開されます。

(LET ((A 5) (B 2))
  (DOLIST (X ((PRINT (+ A B)))) X))

((PRINT (+ A B)))は有効な式ではないため、これは無効です。マクロ展開でインターンシンボルを使用すると変数キャプチャが発生する可能性があるという問題もありますが、それは直接関連していません(PCLで詳細を参照してください)。

ここでDOLISTを使用する必要はなく、正しく実行するためにコンパイルされます(すべてのサブフォームを無名関数に変換してリストに貼り付け、順番にfuncallしてから、PROGNの動作に準拠するために最終結果を保存する必要があります)。PROGNを使用するか、LETに暗黙のPROGNが含まれているため、バッククォートメカニズムの@機能を使用してボディをスプライスするだけです。

(defmacro mylet (args &body exp) `(let ,args ,(cons 'progn exp)))

(defmacro mylet (args &body exp) `(let ,args ,@exp))
于 2011-06-01T09:37:30.840 に答える