0

Practical Common Lispの最初の例(データベースの例)では、作成者はマクロといくつかのサポート関数を使用して、という名前のより大きな関数を置き換えwhereます。が関数の場合、コードwhereは正常に機能しますが、マクロの設定では「未定義の変数」および「バインドされていない変数」のエラーが返されます。(元の関数をコメントアウトし、Emacsを再起動し、whereマクロを追加したらファイルを再コンパイルしたことに注意してください。)

例によれば、マクロはでROWはなくで評価する必要があるため、REPLでキャッチされたスタイル警告は私にとって最も疑わしいものです。CDなぜROW未使用なのですか?この警告を解決するにはどうすればよいですか?

これはREPLに出力されます:

; in: SELECT (WHERE :TITLE "Animals" :RIPPED T)
;     (WHERE :TITLE "Animals" :RIPPED T)
; ==>
;   #'(LAMBDA (ROW)
;       (AND (EQUAL (GETF CD :TITLE) "Animals") (EQUAL (GETF CD :RIPPED) T)))
; 
; caught STYLE-WARNING:
;   The variable ROW is defined but never used.

; in: SELECT (WHERE :TITLE "Animals" :RIPPED T)
;     (WHERE :TITLE "Animals" :RIPPED T)
; --> FUNCTION AND IF EQUAL 
; ==>
;   (GETF CD :TITLE)
; 
; caught WARNING:
;   undefined variable: CD
; 
; compilation unit finished
;   Undefined variable:
;     CD
;   caught 1 WARNING condition
;   caught 1 STYLE-WARNING condition

これは、デバッグスペースに出力されます。

The variable CD is unbound.
   [Condition of type UNBOUND-VARIABLE]

これが私の.lispファイルのサポート関数とマクロです:

; this function is used in both implementations. *db* is a (global) database
(defun select (selector-fn)
  (remove-if-not selector-fn *db*))

(defun make-comparison-expr (field value)
  `(equal (getf cd ,field) ,value))

(defun make-comparisons-list (fields)
  (loop while fields
       collecting (make-comparison-expr (pop fields) (pop fields))))

(defmacro where (&rest clauses)
  `#'(lambda (row) (and ,@(make-comparisons-list clauses))))

私はSBCL、Emacs、Slimeを使用しています。

4

1 に答える 1

2

私が使用しているPracticalCommonLispのバージョンにエラーがあることがわかりました。質問に本へのリンクを追加しているときに、これを発見しました。Webバージョンにはここに正しい例があります。

マクロは次のように定義する必要があります。cdとは対照的に読み取りますrow

(defmacro where (&rest clauses)
  `#'(lambda (cd) (and ,@(make-comparisons-list clauses))))

ラムダ関数とそれが呼び出す関数が変数名(cdこの場合)を共有する必要があることに気づきませんでした。

これがあまりにもローカライズされていると見なされるかどうかはわかりませんが、この努力の結果、どこかに文書化したかったので、今のところここにあります。

于 2013-02-10T05:12:16.520 に答える