0

Practical Common Lisp的第一个示例(数据库示例)中,作者使用了一个宏和几个支持函数来替换一个更大的函数,名为where. 当where是函数时,代码工作正常,但宏设置返回“未定义变量”和“未绑定变量”错误。(请注意,我注释掉了原始函数,重新启动了 Emacs 并在添加where宏后重新编译了我的文件。)

根据示例,REPL 中捕获的样式警告对我来说是最可疑的,因为宏应该使用ROW而不是评估。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

我发现这是我正在使用的 Practical Common Lisp 版本中的错误。我在向我的问题添加本书链接时发现了这一点。网络版在这里有正确的例子。

事实证明,宏应该定义如下。它读cd作与row

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

我没有意识到 lambda 函数和它调用的函数必须共享变量名(cd在这种情况下)。

我不确定这是否被认为过于本地化,但经过所有这些努力,我想在某个地方记录它,所以现在就在这里。

于 2013-02-10T05:12:16.520 回答