【问题标题】:Neater way of prying a DECLARE from a &body从 &body 中撬出 DECLARE 的更简洁的方法
【发布时间】:2012-03-22 23:28:08
【问题描述】:

我正在编写一个生成DEFUN 调用的宏——因此,我想确保宏正文中的任何DECLAREs 都紧跟在DEFUN 之后。这是我所拥有的:

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

不幸的是,它相当丑陋,而且这里发生的事情不一定很明显。你能想到更好的方法吗?

【问题讨论】:

    标签: macros lisp common-lisp


    【解决方案1】:

    您的解决方案不完整,因为可能有一个或多个声明。

    虽然您可以为此使用一些现成的功能,但它有助于对在类似情况下有用的技术进行很好的研究。

    如果你有表格列表

    (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,因为表单可能不是 conses,所以:

    (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 返回原始列表的子结构而不是副本这一事实;它只是沿着列表前进以寻找该指针,并将所有先前的项目作为新列表返回。

    【讨论】:

    • 哇,感谢您的广泛评论!我可能需要更多地了解我的序列/列表操作;使用MEMBER 获得这样的子列表非常整洁。
    【解决方案2】:

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

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

    parse-body 函数与您的问题特别相关。

    【讨论】:

    • 谢谢!这个好像是车票!这引发了另一个问题,我将单独发布。
    【解决方案3】:

    没有对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))))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-04
      • 1970-01-01
      • 1970-01-01
      • 2011-04-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多