2

我正在通过 Practical Common Lisp 工作。我得到了一个例子,你定义了一个与一些附加功能deftest类似的宏。defun这让我想到能够添加一个文档字符串会很好。我发现以下两项都有效,但其中一项更正确吗?是否有一种“正确”的方式来实现类似可选文档字符串的行为defun

(defmacro deftest (name parameters &body body)
  (let ((docstring ""))
    (when (stringp (car body)) (setf docstring (car body) body (cdr body)))
    `(defun ,name ,parameters
       ,docstring
       (let ((*test-name* (append *test-name* (list ',name))))
         ,@body))))

(defmacro deftest (name parameters &optional docstring &body body)
  (when (not (stringp docstring)) (setf docstring ""))
  `(defun ,name ,parameters
     ,docstring
     (let ((*test-name* (append *test-name* (list ',name))))
       ,@body)))
4

1 回答 1

4

通常,您可能希望从函数体中解析出可能的文档字符串和任何声明,因此您可以将声明放在它们所属的位置。我使用这样的东西:

(defun parse-body (body)
    (multiple-value-bind (docstring decls/forms)
        (if (stringp (first body))
            (values (first body) (rest body))
          (values nil body))
      (loop for remainder on decls/forms
            while (and (not (null remainder))
                       (consp (first remainder))
                       (eql (car (first remainder)) 'declare))
            collect (first remainder) into decls
            finally (return (values docstring decls remainder)))))

然后你deftest会是

(defmacro deftest (name parameters &body body)
  (multiple-value-bind (docstring decls forms) (parse-body body)
    `(defun ,name ,parameters
       ,@(if docstring (list docstring) '())
       ,@decls
       (let ((*test-name* (append *test-name* (list ',name))))
         ,@forms))))

我希望我可以说我有一个标准parse-body函数,但我没有:我每次都写一个新函数。

于 2021-02-25T11:43:10.317 回答