Lisp评估在未绑定变量上中止

时间:2013-02-10 05:12:17

标签: macros lambda elisp sbcl

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和史莱姆。

1 个答案:

答案 0 :(得分:2)

我发现在我使用的Practical Common Lisp版本中出现错误。我发现这一点,因为我在我的问题中添加了一本书的链接。 Web版本具有正确的示例here

事实证明,宏应定义如下。它显示为cd而不是row

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

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

我不确定这是否被认为过于本地化,但在完成所有这些努力之后我想在某处记录它,所以现在就是这样。