反引号字符串插值

Backquote String Interpolation

是否可以使用lisp的宏来做字符串插值?

例如,我可以制作这样的宏吗:

(defmacro test (a) `",a")

那么 (test abc) returns "abc" 作为一个字符串?我可能会通过引用它并将该引号转换为字符串来作弊,但这不适用于像“9:00”这样的参数(没有双引号)。

有关字符串插值,请参阅 format. eg. (format nil "~a" a) does what you want. In Practical Common Lisp there are some format recipes

quasiquote 和 unquote 仅适用于列表,不适用于其他序列。

宏是代码的转换。这不是运行时发生的事情。例如。当你有像 (my-macro x) 这样的代码时,其中 x 在运行时将是一个字符串,宏只看到符号。它无法知道它在扩展时是什么类型。

反引号,无论是否在宏中,都不会这样做:

[1]> (defmacro test (a) `",a")
TEST
[2]> (test oh-no)
",a"

你可以做的就是使用format,如下:

[3]> (defun interp (name) (format nil "Hi, my name is ~A" name))
INTERP
[4]> (interp "Steve")
"Hi, my name is Steve"

Lisp 宏对已经被 lisp reader 读取的参数进行操作。正因为如此,宏不能改变它的参数被读取的方式,如果你传递一个参数,当你试图读取它时,它会发出错误信号,例如9:00(test 9:00) 中,reader 甚至在宏开始 运行 之前就发出错误信号 运行。

reader也是可以自定义的。不是让您以直接的方式将 9:00 读作 "9:00" 的方式,但是例如您可以编写一个简短的 reader 宏,将 @9:00 读作 "9:00" 或作为日期对象。

编辑:像这样:

(defvar *arguments-rt* (copy-readtable ()))

(defun timestring-reader (stream char &optional count)
  (declare (ignore char count))
  (with-output-to-string (s)
    (loop repeat 4 do (write-char (read-char stream) s))))

(set-macro-character #\@ #'timestring-reader () *arguments-rt*)

(let ((*readtable* *arguments-rt*))
  (let ((args "dinner @9:00"))
    (with-input-from-string (stream args)
      (loop for arg = (read stream () ())
            while arg collect arg))))

-> (DINNER "9:00")