我想在常见的lisp中执行一个宏,它应该在其中一个参数中包含由插槽和字符串组成的列表。这是原型:
(defclass time-info ()
((name :initarg name)
(calls :initarg calls)
(second :initarg second)
(consing :initarg consing)
(gc-run-time :initarg gc-run-time)))
(defun print-table (output arg-list time-info-list) ())
我们的想法是根据定义其结构的arg-list打印一个表。以下是对函数调用的示例:
(print-table *trace-output*
'("|" name "||" calls "|" second "\")
my-time-info-list)
这将在跟踪输出的ascII中打印一个表。问题是,我不知道如何明确地获取列表的元素以在宏的不同部分使用它们。
我还不知道怎么做,但我确信可以做到。也许你可以帮助我:)。
答案 0 :(得分:1)
我会以format
为基础。我们的想法是构建一个格式字符串
来自您的arg-list
。
我为此定义了一个辅助函数:
(defun make-format-string-and-args (arg-list)
(let ((symbols ()))
(values (apply #'concatenate 'string
(mapcar (lambda (arg)
(ctypecase arg
(string
(cl-ppcre:regex-replace-all "~" arg "~~"))
(symbol
(push arg symbols)
"~a")))
arg-list))
(nreverse symbols))))
请注意,~
字符串必须加倍format
才能将其转义。
然后,打印宏本身只生成mapcar
format
:
(defmacro print-table (stream arg-list time-info-list)
(let ((time-info (gensym)))
(multiple-value-bind (format-string arguments)
(make-format-string-and-args arg-list)
`(mapcar (lambda (,time-info)
(format ,stream ,format-string
,@(mapcar (lambda (arg)
(list arg time-info))
arguments)))
,time-info-list)))
然后你可以这样称呼它:
(print-table *trace-output*
("|" name "||" calls "|" second "\\")
my-time-info-list)
请注意代码中的以下错误:
您需要在字符串中转义\
。
Second
已经是从common-lisp
导出的函数名称
包。你不应该用通用函数来破坏它。
答案 1 :(得分:1)
您需要更准确地满足您的要求。宏和函数是不同的东西。数组和列表也不同。
我们需要迭代TIME-INFO-LIST
。这是第一个DOLIST
。
该表有一条线的描述。描述中的每个项目都是插槽名称或字符串。所以我们迭代描述。那是第二个DOLIST
。只打印一个字符串。符号是一个插槽名称,我们从当前time-info
实例中检索插槽值。
(defun print-table (stream line-format-description time-info-list)
(dolist (time-info time-info-list)
(terpri stream)
(dolist (slot-or-string line-format-description)
(princ (etypecase slot-or-string
(string slot-or-string)
(symbol (slot-value time-info slot-or-string)))
stream))))
测试:
> (print-table *standard-output*
'("|" name "||" calls "|" second "\\")
(list (make-instance 'time-info
:name "foo"
:calls 100
:second 10)
(make-instance 'time-info
:name "bar"
:calls 20
:second 20)))
|foo||100|10\
|bar||20|20\
答案 2 :(得分:0)
首先,你可能不想在那里引用,如果你正在使用一个宏(如果你正在使用一个函数,你确实需要它)。其次,您是否希望在分隔符和值之间添加任何填充?第三,你可能最好使用一个函数,而不是一个宏。
您似乎也可以互换地使用“数组”和“列表”。它们在Common Lisp中完全不同。有些操作适用于通用序列,但通常使用一种方法迭代列表,另一种方法迭代数组。