Lisp:将 &rest 参数传递给宏

Lisp: Pass &rest parameters to a macro

我正在尝试构建一个函数来访问数据库中的记录:

(select :title "milk" :rating 7)

但是,它只是返回数据库中的所有记录。我相信这是因为我将 &rest 参数传递给宏并且它按字面解释参数名称 "fields"。我尝试从我的宏中删除 &rest,但随后我收到关于未传递列表的错误。我试过在各个地方调用(列表字段)无济于事(在宏中,在调用宏的函数中,在宏调用的函数中)。

以下代码按预期工作:

(select-custom (where :title "milk" :rating 7))

并且 returns 仅匹配参数的记录。

源代码:

(defun select (&rest fields)
  (select-custom (where fields)))

(defun select-custom (selector-function)
  (remove-if-not selector-function *db*))

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

(defun make-comparison-list (fields)
  (loop while fields
        collecting (make-comparison-exp (pop fields) (pop fields))))

(defun make-comparison-exp (field value)
  `(equal (getf cd ,field) ,value))

最好的解决方案是创建 where 的函数版本。但是作为一个简单的拼凑,你可以使用 eval

(defun select (&rest fields)
    (select-custom (eval `(where ,@fields))))

您可以将 select 改为宏

(defmacro select (&rest fields)
  `(select-custom (where ,@fields)))

你可以检查一下

(macroexpand-1 '(select :title "milk" :rating 7))

returns

(SELECT-CUSTOM (WHERE :TITLE "milk" :RATING 7))