从一个&身体撬开DECLARE的更好的方式

时间:2012-03-22 23:28:09

标签: macros lisp common-lisp

我正在编写一个生成DEFUN调用的宏 - 我希望确保宏的正文中的任何DECLAREDEFUN之后立即放置。这就是我所拥有的:

(defmacro defsynced (name (&rest args) &body body)
  (let* ((decl (if (eql (caar body) 'cl:declare)
                   (list (car body))))
         (body (if decl
                   (cdr body)
                   body)))
    `(defun ,name ,args
       ,@decl
       (bordeaux-threads:with-lock-held (*request-lock*)
         ,@body))))

不幸的是,它相当难看,并不一定明显在这里发生了什么。有没有更好的方法可以想到?

3 个答案:

答案 0 :(得分:3)

您的解决方案尚未完成,因为可以有一个或更多声明。

虽然你可以使用一些现成的功能,但它可以很好地研究一种在类似情况下有用的技术。

如果您有表格列表

(alpha beta x epsilon ... omega)

其中x是您要对列表进行拆分的感兴趣项目,您可以使用member函数查找以x开头的子列表,然后查找ldiff函数获取排除(alpha beta)的列表(x epsilon omega)的前缀。第一步:

(member-if-not (lambda (x) (eq x 'declare)) '(declare declare 3 4 5))

-> (3 4 5)

当然,我们正在寻找(declare ...)而不是declare。我们不能使用:key #'car,因为表单可能不合适,所以:

(member-if-not (lambda (x) (and (consp x) (eq (car x) 'declare)))
               '((declare foo) (declare bar) 3 4 5))
-> (3 4 5)

现在如何获取声明和剩余表单:

(defun separate-decls-and-body (body)
  (let* ((just-the-code (member-if-not (lambda (x)
                                         (and (consp x) (eq (car x) 'declare)))
                                        body))
         (just-the-decls (ldiff body just-the-code)))
    (values just-the-decls just-the-code)))

试验:

> (separate-decls-and-body '((declare (optimize (speed 3))) (declare (type)) 1 2 3))
((DECLARE (OPTIMIZE (SPEED 3))) (DECLARE (TYPE))) ;
(1 2 3)

> (separate-decls-and-body '((declare (optimize (speed 3)))))
((DECLARE (OPTIMIZE (SPEED 3)))) ;
NIL

> (separate-decls-and-body '())
NIL ;
NIL

> (separate-decls-and-body '(1 2 3))
NIL ;
(1 2 3)

member家庭和ldiff是您的朋友。 ldiff基于member返回原始列表的子结构而不是副本的事实;它只是在列表中向下搜索该指针,并将所有先前项目作为新列表返回。

答案 1 :(得分:1)

由于声明解析可能很棘手,因此有一个名为parse-declarations的库可以帮助解决它。它可以从Quicklisp获得。

(ql:quickload "parse-declarations-1.0")

parse-body功能与您的问题特别相关。

答案 2 :(得分:1)

没有对loop神的仪式性牺牲,没有答案是完整的:

(defun separate-decls-and-body (body)
  (loop for sub-body on body
        for form = (first sub-body) 
        until (or (atom form) (not (eq (first form) 'declare)))
        collecting form into decls
        finally (return (values decls sub-body))))