如何在反引号外扩展列表 - 宏定义

时间:2012-02-13 15:45:50

标签: common-lisp

我正在尝试实现一个宏,它将无限的三元组参数列表扩展为lambda函数以检查参数(对象)。

e.g。

(where >= amount 5 equalp name "george")

=>

#'(lambda (arg)
          (and
            (>= (amount arg) 5)
            (equalp (name arg) "george")))

我对这个宏定义非常接近:

(defmacro where (&rest list-of-argument-triplets )
   `#'(lambda (arg)
        (and
          ,(do ( (counter 0 (+ counter 3)) (liste (list)))
               ( (>= counter (list-length list.of-argument-triplets)) liste)
                 (push `( ,(nth counter list-of-argument-triplets)
                          ( ,(nth (+ counter 1) list-of-argument-triplets) arg)
                          ,(nth (+ counter 2) list-of-argument-triplets)
                          liste)))))

但这会扩展到

#'(lambda (arg)
    (and ((>= (amount arg) 5)
          (equalp (name arg) "george"))))

这是“和”之后的一个括号。作为结论,我必须在结果表单前面使用@,然后处理“@list” 好像它是一个参数名,因此我得到一个无值错误,而不是扩展列表。

        *** - RETURN-FROM: variable @LISTE has no value

我该如何解决?

1 个答案:

答案 0 :(得分:1)

代码气味:您使用NTH访问列表中的元素。

我首先要定义一个辅助函数,它从平面列表中得出三个元素列表的列表:

(defun triplets (list)
  (loop while list
        collect (list (pop list)
                      (pop list)
                      (pop list))))

CL-USER 1 > (triplets '(a b c d e f g h i))
((A B C) (D E F) (G H I))

然后编写宏稍微简单:

(defmacro where (&rest flat-triplets)
  `#'(lambda (arg)
       (and
         ,@(mapcar (lambda (triplet)
                     (destructuring-bind (fn accessor item)
                         triplet
                       `(,fn (,accessor arg) ,item)))
                   (triplets flat-triplets))))


CL-USER 2 > (macroexpand-1 '(where >= amount 5 equalp name "george"))
(FUNCTION (LAMBDA (ARG) (AND (>= (AMOUNT ARG) 5) (EQUALP (NAME ARG) "george"))))
T