Lisp のバッククォート読み取りマクロに問題があります。逆引用符を埋め込む必要があると思われるマクロを記述しようとすると (たとえば、``(w ,x ,,y)
Paul Graham のANSI Common Lispの399 ページから)、コンパイルできるようにコードを記述する方法がわかりません。通常、私のコードは、「バッククォート内にカンマがありません」で始まる一連のエラーを受け取ります。適切に評価されるコードを作成する方法について、誰かがガイドラインを提供できますか?
例として、現在、次の形式でルールを記述し'(function-name column-index value)
、述語ラムダ本体を生成して、特定の行の によってインデックス付けされた要素column-index
がルールを満たすかどうかを判断するマクロが必要です。rule を指定してこのマクロを呼び出すと'(< 1 2)
、次のようなラムダ本体が生成されます。
(lambda (row)
(< (svref row 1) 2))
これで私ができる最高の刺し傷は次のとおりです。
(defmacro row-satisfies-rule (rule)
(let ((x (gensym)))
`(let ((,x ,rule))
(lambda (row)
(`,(car ,x) (svref row `,(cadr ,x)) `,(caddr ,x))))))
評価時に、SBCL は次のエラー レポートを吐き出します。
; in: ROW-SATISFIES-RULE '(< 1 2)
; ((CAR #:G1121) (SVREF ROW (CADR #:G1121)) (CADDR #:G1121))
;
; caught ERROR:
; illegal function call
; (LAMBDA (ROW) ((CAR #:G1121) (SVREF ROW (CADR #:G1121)) (CADDR #:G1121)))
; ==>
; #'(LAMBDA (ROW) ((CAR #:G1121) (SVREF ROW (CADR #:G1121)) (CADDR #:G1121)))
;
; caught STYLE-WARNING:
; The variable ROW is defined but never used.
; (LET ((#:G1121 '(< 1 2)))
; (LAMBDA (ROW) ((CAR #:G1121) (SVREF ROW (CADR #:G1121)) (CADDR #:G1121))))
;
; caught STYLE-WARNING:
; The variable #:G1121 is defined but never used.
;
; compilation unit finished
; caught 1 ERROR condition
; caught 2 STYLE-WARNING conditions
#<FUNCTION (LAMBDA (ROW)) {2497F245}>
必要なコードを生成するマクロを作成するにはどうすればよいですか? 特に、どのように実装すればよいrow-satisfies-rule
ですか?
Ivijay と discipulus のアイデアを使用して、マクロを修正して、コンパイルして動作するようにし、フォームを引数として渡すこともできるようにしました。row
コードをよりスムーズにするために引数として含めることを決定したため、最初に計画したマクロとは少し異なって実行されます。しかし、それは罪のように醜いです。への呼び出しなしで同じように実行するように、それをクリーンアップする方法を知っている人はいますeval
か?
(defmacro row-satisfies-rule-p (row rule)
(let ((x (gensym))
(y (gensym)))
`(let ((,x ,row)
(,y ,rule))
(destructuring-bind (a b c) ,y
(eval `(,a (svref ,,x ,b) ,c))))))
また、実行時に引数を適切に評価するためのコードを生成するマクロを取得するクリーンで Lispy の方法の説明も大歓迎です。