在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和史莱姆。
答案 0 :(得分:2)
我发现在我使用的Practical Common Lisp版本中出现错误。我发现这一点,因为我在我的问题中添加了一本书的链接。 Web版本具有正确的示例here。
事实证明,宏应定义如下。它显示为cd
而不是row
:
(defmacro where (&rest clauses)
`#'(lambda (cd) (and ,@(make-comparisons-list clauses))))
我没有意识到lambda函数和它调用的函数必须共享变量名(在这种情况下为cd
)。
(我不确定这是否被认为过于本地化,但在完成所有这些努力之后我想在某处记录它,所以现在就是这样。)