Pergunta

During the first example (the database example) in Practical Common Lisp, the author uses a macro and a couple support functions in order to replace a larger function, named where. The code works fine when where is a function, but the macro setup returns "undefined variable" and "unbound variable" errors. (Note that I commented out the original function, restarted Emacs and recompiled my file once adding the where macro.)

The caught style-warning in the REPL is most suspect to me since the macro should evaluate with ROW rather than CD, according to the example. Why is ROW unused? How do I resolve this warning?

This is printed in the 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

This is printed in the debug space:

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

Here are the support functions and macro in my .lisp file:

; 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))))

I'm using SBCL, Emacs and Slime.

Foi útil?

Solução

I found that it is an error in the version of Practical Common Lisp that I am using. I discovered this as I was adding to my question a link to the book. The web version has the correct example here.

It turns out the macro should be defined as follows. It reads cd as opposed to row:

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

I didn't realize the lambda function and the function that it calls have to share the variable name (cd in this case).

(I'm not sure if this is considered too localized, but after all this effort I wanted to document it somewhere, so here it is for now.)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top