Macros 反引号字符串插值

Macros 反引号字符串插值,macros,lisp,common-lisp,Macros,Lisp,Common Lisp,是否可以使用lisp的宏进行字符串插值 例如,我可以制作如下宏: (defmacro test (a) `",a") (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 (wr

是否可以使用lisp的宏进行字符串插值

例如,我可以制作如下宏:

(defmacro test (a) `",a")
(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")

所以(测试abc)返回“abc”作为字符串?我可能会通过引用它并将其转换为字符串来作弊,但这对“9:00”(没有双引号)之类的参数不起作用。

有关字符串插值,请参阅。例如,
(格式为nil”~a“a)
满足您的需求。里面有一些

QUISQUOTE和unquote仅适用于列表,而不适用于其他序列


宏是代码的转换。。这不是在运行时发生的事情。例如,如果运行时有类似于
(我的宏x)
的代码,其中
x
将是一个字符串,则宏只能看到符号。它在扩展时不知道它是什么类型

反引号,无论是否在宏中,都不会执行此操作:

[1]> (defmacro test (a) `",a")
TEST
[2]> (test oh-no)
",a"
您可以做的是使用,如下所示:

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

Lisp宏对已被Lisp读取器读取的参数进行操作。正因为如此,宏无法更改其参数的读取方式,如果您传递的参数在尝试读取时会发出错误信号,例如
(test 9:00)
中的
9:00
,则读取器甚至会在宏开始运行之前发出错误信号

阅读器也是可定制的。不是以一种可以让您以简单的方式将
9:00
读为
“9:00”
,而是可以编写一个简短的读取器宏,将
@9:00
读为
“9:00”
,或作为日期对象

编辑:类似这样的内容:

(defmacro test (a) `",a")
(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")

所以我必须使用字符串?对于
9:00
,是的,您需要。对于其他一些符号,您不必这样做,但对于此类数据,使用字符串通常是一个非常好的主意。请参阅m-n的回答,以更好地解释原因。您的问题是“是否可以使用lisp的宏进行字符串插值?”是的,您必须使用字符串进行字符串插值。如果幻想语法
”,一个“
起作用,那将是一种字符串操作形式。试试看。@Dan:这对我的例子不起作用9:00试图查找一个名为“9”的包,但该包不存在。@i人类,您需要逃离它。例如,
'9:00
'9:00
。谢谢。我之所以尝试跳转使其成为字符串,是因为我在命令行参数的连接版本上使用了从字符串读取。这导致使用双引号很麻烦,因为bash没有将引号传递给lisp。“@”在bash中没有什么特别的地方,所以我将采用您的想法。@iHuman我添加了一个快速示例。在fresh readtable(使用
copy readtable
创建)中设置reader宏并在本地绑定
*readtable*
可以防止更改在遥远的代码中产生意外的影响。如果您只想以结构化的形式获取命令行参数,请查看所有的命令行解析器(或直接使用它们).