Common lisp Common Lisp:传递宏生成的lambda以删除,如果不是,则会导致错误
当我在书中提供的最终产品中遇到错误时,我正在跟随书中的第一个示例项目 该项目是一个基本的数据库,存储有关CD的信息。它支持select和update语句与where宏一起使用 我已经使用clisp和sbcl编译器测试了代码,两个编译器都出现了相同的错误 代码如下:Common lisp Common Lisp:传递宏生成的lambda以删除,如果不是,则会导致错误,common-lisp,Common Lisp,当我在书中提供的最终产品中遇到错误时,我正在跟随书中的第一个示例项目 该项目是一个基本的数据库,存储有关CD的信息。它支持select和update语句与where宏一起使用 我已经使用clisp和sbcl编译器测试了代码,两个编译器都出现了相同的错误 代码如下: (defvar *db*) (defun make-cd (title artist rating ripped) (list :title title :artist artist :rating rating :ripped
(defvar *db*)
(defun make-cd (title artist rating ripped)
(list :title title :artist artist :rating rating :ripped ripped))
(defun add-record (cd) (push cd *db*))
(defun dump-db ()
(format t "~{~{~a:~10t~a~%~}~%~}" *db*))
(defun prompt-read (prompt)
(format *query-io* "~a: " prompt)
(force-output *query-io*)
(read-line *query-io*))
(defun prompt-for-cd ()
(make-cd
(prompt-read "Title")
(prompt-read "Artist")
(or (parse-integer (prompt-read "Rating") :junk-allowed t) 0)
(y-or-n-p "Ripped [y/n]: ")))
(defun add-cds ()
(loop (add-record (prompt-for-cd))
(if (not (y-or-n-p "Another? [y/n]: ")) (return))))
(defun save-db (filename)
(with-open-file (out filename
:direction :output
:if-exists :supersede)
(with-standard-io-syntax
(print *db* out))))
(defun load-db (filename)
(with-open-file (in filename)
(with-standard-io-syntax
(setf *db* (read in)))))
(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))))
(defun where (&rest clauses)
`#'(lambda (cd) (and ,@(make-comparisons-list clauses))))
(defun update (selector-fn &key title artist rating (ripped nil ripped-p))
(setf *db*
(mapcar
#'(lambda (cd)
(when (funcall selector-fn cd)
(if title (setf (getf cd :title) title))
(if artist (setf (getf cd :artist) artist))
(if rating (setf (getf cd :rating) rating))
(if ripped-p (setf (getf cd :ripped) ripped)))
cd)
*db*)))
(defun delete-rows (selector-fn)
(setf *db* (remove-if selector-fn *db*)))
以下是产生错误的调用:
(select (where :artist "Dixie Chicks"))
基本上,这个电话的内容如下。where宏给出一个lambda表达式,该表达式接受cd并充当谓词,以确定cd是否具有特定字段的特定值
在此特定调用中,where宏扩展为:
#'(lambda (cd) (and (equal (getf cd :artist) "Dixie Chicks")))
以下是db当前的定义:
((:TITLE "Fly" :ARTIST "Dixie Chicks" :RATING 7 :RIPPED T)
(:TITLE "Home" :ARTIST "Dixie Chicks" :RATING 9 :RIPPED T)
(:TITLE "Lyle Lovett" :ARTIST "Lyle Lovett" :RATING 9 :RIPPED T)
(:TITLE "Give Us a Break" :ARTIST "Limpopo" :RATING 10 :RIPPED T)
(:TITLE "Rockin' the Suburbs" :ARTIST "Ben Folds" :RATING 6 :RIPPED T)
(:TITLE "Naive" :ARTIST "The Kooks" :RATING 6 :RIPPED T)
(:TITLE "It's the end of the world as we know it" :ARTIST "REM" :RATING 6
:RIPPED T)
(:TITLE "We Walk" :ARTIST "REM" :RATING 8 :RIPPED T))
以下是上述调用产生的错误:
The value
#'(LAMBDA (CD) (AND (EQUAL (GETF CD :ARTIST) "Dixie Chicks")))
is not of type
(OR FUNCTION SYMBOL)
when binding SB-IMPL::PREDICATE
[Condition of type TYPE-ERROR]
((:TITLE "Fly" :ARTIST "Dixie Chicks" :RATING 7 :RIPPED T)
(:TITLE "Home" :ARTIST "Dixie Chicks" :RATING 9 :RIPPED T))
以下是上述调用的预期结果:
The value
#'(LAMBDA (CD) (AND (EQUAL (GETF CD :ARTIST) "Dixie Chicks")))
is not of type
(OR FUNCTION SYMBOL)
when binding SB-IMPL::PREDICATE
[Condition of type TYPE-ERROR]
((:TITLE "Fly" :ARTIST "Dixie Chicks" :RATING 7 :RIPPED T)
(:TITLE "Home" :ARTIST "Dixie Chicks" :RATING 9 :RIPPED T))
在寻求帮助之前,我花了大量的时间来检查这段代码,但是由于我对CommonLisp非常原始的了解,我似乎找不到罪魁祸首
提前谢谢 您错过了一个关键点: 现在,您只需将
make comparison list
返回的列表包装到和
以及匿名函数中,您可以在where
宏本身中执行此操作。使用后引号生成一个模板,您可以通过插入生成比较列表的值来填充该模板,这很简单
(defmacro where (&rest clauses)
`#'(lambda (cd) (and ,@(make-comparisons-list clauses))))
在这个版本中,其中
是宏,而不是函数;i、 e.您需要使用defmacro
来定义它,而不是defun
您错过了一个关键点:
现在,您只需将make comparison list
返回的列表包装到和
以及匿名函数中,您可以在where
宏本身中执行此操作。使用后引号生成一个模板,您可以通过插入生成比较列表的值来填充该模板,这很简单
(defmacro where (&rest clauses)
`#'(lambda (cd) (and ,@(make-comparisons-list clauses))))
在这个版本中,是一个宏,而不是一个函数;i、 e.您需要使用defmacro
来定义它,而不是defun
问题很容易找到。如果你知道去哪里找
错误表明#'(LAMBDA(CD)(和(EQUAL(GETF CD:ARTIST)“Dixie Chicks”))
不是函数或符号
这是什么?这是一份清单
CL-USER 9 > '#'(LAMBDA (CD) (AND (EQUAL (GETF CD :ARTIST) "Dixie Chicks")))
(FUNCTION (LAMBDA (CD) (AND (EQUAL (GETF CD :ARTIST) "Dixie Chicks"))))
CL-USER 10 > (type-of *)
CONS
但是cons
不是函数对象或符号
所以你只需要找到为什么你得到这个列表而不是一个函数对象。然后可以看到,其中
返回列表。如果中的是一个宏,它将创建此列表作为源,然后将其计算为函数对象。问题很容易找到。如果你知道去哪里找
错误表明#'(LAMBDA(CD)(和(EQUAL(GETF CD:ARTIST)“Dixie Chicks”))
不是函数或符号
这是什么?这是一份清单
CL-USER 9 > '#'(LAMBDA (CD) (AND (EQUAL (GETF CD :ARTIST) "Dixie Chicks")))
(FUNCTION (LAMBDA (CD) (AND (EQUAL (GETF CD :ARTIST) "Dixie Chicks"))))
CL-USER 10 > (type-of *)
CONS
但是cons
不是函数对象或符号
所以你只需要找到为什么你得到这个列表而不是一个函数对象。然后可以看到,其中
返回列表。如果where
是一个宏,它将创建这个列表作为源,然后将其计算为一个函数对象。where
应该是一个defmacro
,而不是defun
(不要忘记在更改后重新编译where
的所有用户)。@sds非常感谢您。我发誓我盯着这个看了两个小时。哎呀。where
应该是defmacro
,而不是defun
(更改后不要忘记重新编译where
的所有用户)。@sds非常感谢。我发誓我盯着这个看了两个小时。哦,这是一个很好的“教他们钓鱼”的答案!所以需要一个“元答案”复选标记。现在这是一个很好的“教他们钓鱼”答案!所以需要一个“元答案”复选标记。