处理插槽和字符串列表中的值

时间:2011-07-26 09:16:01

标签: lisp common-lisp

我想在常见的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中打印一个表。问题是,我不知道如何明确地获取列表的元素以在宏的不同部分使用它们。

我还不知道怎么做,但我确信可以做到。也许你可以帮助我:)。

3 个答案:

答案 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中完全不同。有些操作适用于通用序列,但通常使用一种方法迭代列表,另一种方法迭代数组。