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

发布于 2024-11-26 15:03:28 字数 604 浏览 3 评论 0原文

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

我还不知道如何做到这一点,但我确信它可以做到。也许你可以帮助我:)

I want to do a macro in common lisp which is supposed to take in one of its arguments a list made of slots and strings. Here is the prototype :

(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) ())

The idea is to print a table based on the arg-list which defines its structure. Here is an example of a call to the function:

(print-table *trace-output*
             '("|" name "||" calls "|" second "\")
             my-time-info-list)

This print a table in ascII on the trace output. The problem, is that I don't know how to explicitely get the elements of the list to use them in the different parts of my macro.

I have no idea how to do this yet, but I'm sure it can be done. Maybe you can help me :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

在梵高的星空下 2024-12-03 15:03:28

我将基于格式。这个想法是构建一个格式字符串
来自您的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 字符串中加倍才能转义它们。

然后,打印宏本身只会生成 formatmapcar

(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 导出的函数名称
    包裹。您不应该使用通用函数来破坏它。

I would base this on format. The idea is to build a format string
from your arg-list.

I define a helper function for that:

(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))))

Note that ~ must be doubled in format strings in order to escape them.

The printing macro itself then just produces a mapcar of 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)))

You can then call it like this:

(print-table *trace-output*
             ("|" name "||" calls "|" second "\\")
             my-time-info-list)

Please note the following errors in your code:

  • You need to escape \ in strings.

  • Second is already a function name exported from the common-lisp
    package. You should not clobber that with a generic function.

神经暖 2024-12-03 15:03:28

您需要更准确地表达您的要求。宏和函数是不同的东西。数组和列表也不同。

我们需要迭代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\

You need to be more precise with your requirements. Macros and Functions are different things. Arrays and Lists are also different.

We need to iterate over the TIME-INFO-LIST. So that's the first DOLIST.

The table has a description for a line. Each item in the description is either a slot-name or a string. So we iterate over the description. That's the second DOLIST. A string is just printed. A symbol is a slot-name, where we retrieve the slot-value from the current time-info instance.

(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))))

Test:

> (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\
鸠书 2024-12-03 15:03:28

首先,如果您使用宏,您可能不希望在那里使用引号(但是,如果您使用函数,则确实需要它)。其次,您希望分隔符和值之间有填充吗?第三,使用函数可能比宏更好。

您似乎还可以互换使用“数组”和“列表”。它们在 Common Lisp 中是完全不同的东西。有些操作适用于通用序列,但通常您会使用一种方法来迭代列表,另一种方法来迭代数组。

First, you probably don't want the quote there, if you're using a macro (you do want it there if you're using a function, however). Second, do you want any padding between your separators and your values? Third, you're probably better off with a function, rather than a macro.

You also seem to be using "array" and "list" interchangeably. They're quite different things in Common Lisp. There are operations that work on generic sequences, but typically you would use one way of iterating over a list and another to iterate over an array.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文