2

一般的なLispマクロは通常、包含接頭辞表記を使用します:(演算子のもの...)

ただし、特別引用符マクロ'は、連結接頭辞表記を使用します:operator stuff、または代わりにoperator(stuff)。

SBCL Common Lispでカスタムマクロを作成したいと思います。これを!と呼びましょう。これは、連結プレフィックス構文を使用して、'と同様に、次のリスト(またはアトム)を操作します。したがって、括弧自体に挿入しなくても、どこでも呼び出すことができます(たとえば、(setq foo!(bar)))。

これはどのように行うことができますか?defmacro構文はどのようになりますか?ありがとう。

4

1 に答える 1

1

それを行うには2つの方法があります。

最初の単純なバリアントは、単一または非常に限られた数のケースでのみ必要であり、プレフィックスとして単一のシンボルのみを使用することに満足している場合に適しています(!例の場合のように)。読み取りマクロを作成できます。具体的には、macro-characterこのような演算子を加算の代わりに使用するように設定します。

(set-macro-character #\! (lambda (stream char)
                           (declare (ignore char))
                           (cons '+ (let ((next (read stream t nil t)))
                                 (if (consp next) next
                                     (list next)))))
CL-USER> !1
1
CL-USER> !(1 2)
3

もう1つの、より複雑で柔軟な方法は、マクロを定義することです。このマクロ内でカスタム変換を適用し、連結プレフィックスコードをインクルードプレフィックスに変換します。foo(bar)このトリックは、通常のLispリーダーがとの両方を同じように読み取るという事実を使用していfoo (bar)ます。つまり、それらを2つの要素に分割します。

このようなマクロの単純なバージョンは、次のようになります。

(defmacro with-prefix-syntax (&body body)
  `(progn ,@(loop :for tail :on body :while body
                  :collect (if (and (not (atom (second tail)))
                                    (fboundp (first tail)))
                               (prog1 (cons (first tail) (second tail)
                                 (setf tail (rest tail)))
                               (first tail)))))

トップレベルのフォームのみを変換します。

CL-USER> (macroexpand-1 '(with-prefix-syntax
                           print(1)))
(PROGN (PRINT 1))
CL-USER> (macroexpand-1 '(with-prefix-syntax
                           1))
(PROGN 1)
CL-USER> (macroexpand-1 '(with-prefix-syntax
                           print(1)
                           2))
(PROGN (PRINT 1) 2)

ただし、下位レベルでは機能しません。

CL-USER> (macroexpand-1 '(with-prefix-syntax
                           print(1)
                           (+ print(2))))
(PROGN (PRINT 1) (+ PRINT (2)))

すべてのレイヤーを再帰的に変換するのはかなり簡単ですが(これは読者の練習問題として残されています:)

于 2012-10-06T14:48:21.223 に答える