Common lisp 拆分格式字符串(格式t…)

Common lisp 拆分格式字符串(格式t…),common-lisp,Common Lisp,有时我喜欢用(格式t..)输出一些文本 为了防止源代码中的长格式字符串无法读取,并使输出易于对齐,我使用了(format t(concatenate'string…) 例如: (format t (concatenate 'string "some output~%" " error-msg: ~a~%" "

有时我喜欢用
(格式t..)
输出一些文本
为了防止源代码中的长格式字符串无法读取,并使输出易于对齐,我使用了
(format t(concatenate'string…)

例如:

(format t (concatenate 'string 
                       "some output~%"
                       "  error-msg: ~a~%"
                       "  uiop-cwd: ~a~%"
                       "  uiop-file-exists: ~a~%")
        "error foo"
        (uiop:getcwd)
        (uiop:file-exists-p "hello_world.bmp"))

在Common Lisp中是否有一种更为惯用且在编译时执行相同操作的方法?

这里有一个等效的格式字符串,它使用format指令,忽略以下换行符和空格(直到下一个可见字符).为了像您那样缩进空格,我在空格前写了强制换行符
~%

(format t 
        "some output~
       ~%   error-msg: ~a~
       ~%   uiop-cwd: ~a~
       ~%   uiop-file-exists: ~a~%"
        "error foo"
        (uiop:getcwd)
        (uiop:file-exists-p "hello_world.bmp"))

(注意,这是一个字符串,因此在编译时不需要进行连接。)

您可以很好地使用以下内容:

(defun fmt (to control/s &rest args-to-format)
  (declare (dynamic-extent args-to-format)) ;?OK
  (apply #'format to (if (listp control/s)
                         (apply #'concatenate 'string control/s)
                       control/s)
         args-to-format))

(define-compiler-macro fmt (&whole form to control/s &rest args-to-format)
  (cond
   ((stringp control/s)
    `(format ,to ,control/s ,@args-to-format))
   ((and (listp control/s)
         (eql (first control/s) 'quote))
    ;; literal
    (destructuring-bind (_ thing) control/s
      (declare (ignore _))
      (print "here")
      (if (and (listp thing) (every #'stringp thing))
          `(format ,to ,(apply #'concatenate 'string thing) ,@args-to-format)
        form)))
   (t
    form)))
编译器宏应确保

(fmt t '("~&foo: ~S~%"
         "bar~%") ...)

将完全没有运行时成本。

您可以使用
#(concatenate…
使其在读取时进行连接。有趣的是,由于简单性,我倾向于另一个答案。但是@jue--“有没有更惯用的编译时方式…?”遗憾的是,惯用和编译时可能会相互矛盾。