如何在共识列表上使用格式迭代能力
How to use format's iteration ability on a list of conses
我知道我可以使用 format
的 ~:{ ~}
运算符直接处理列表列表,例如
CL-USER> (format t "~:{<~A,~A> ~}~%" '((1 2) (3 4)))
<1,2> <3,4>
但现在我有一个缺点列表,例如((1 . 2) (3 . 4))
和表达式
(format t "~:{<~A,~A> ~}~%" '((1 . 2) (3 . 4)))
导致 SBCL 投诉
The value
2
is not of type
LIST
是否有任何 format
魔术可以在不使用 do
或 loop
的额外迭代的情况下实现这一目的?
我基本上看到了 4 个选项
不要对整个列表使用格式
直接的解决方法是避免问题:
(loop
for (k . v) in '((1 . 2) (3 . 4))
do (format t "<~a,~a> " k v))
自定义格式功能
或者,使用 Tilde Slash 调用打印 cons-cells 的函数:
(defun cl-user::pp-cons (stream cons colonp atsignp)
(declare (ignore colonp atsignp))
(format stream "~a, ~a" (car cons) (cdr cons)))
(format nil "~/pp-cons/" (cons 1 2))
=> "1, 2"
请注意,如果您不指定包,则该函数必须在 CL-USER 包中。如果要自定义单元格的打印方式,需要通过特殊变量传递格式:
(defvar *fmt* "(~s . ~s)")
(defun cl-user::pp-cons (stream cons colonp atsignp)
(declare (ignore colonp atsignp))
(format stream *fmt* (car cons) (cdr cons)))
然后:
(let ((*fmt* "< ~a | ~a >"))
(format t "~/pp-cons/" (cons 1 2)))
=> < 1 | 2 >
打印时转换
构建一个新列表,其中不正确的列表被正确的列表替换:
(format t
"~:{<~a,~a> ~}~%"
(series:collect 'list
(series:mapping (((k v) (series:scan-alist '((1 . 2) (3 . 4)))))
(list k v))))
缺点是转换需要分配内存,只是为了打印。
更改数据格式
如果适当的列表适合打印,也许它们也适合其他操作。许多标准函数都需要适当的列表。请注意,列表 ((1 2) (3 4))
仍然是一个列表,值只是包装在一个 cons-cell 中。如果您决定从一开始就使用这种格式,则无需转换您的列表。
我知道我可以使用 format
的 ~:{ ~}
运算符直接处理列表列表,例如
CL-USER> (format t "~:{<~A,~A> ~}~%" '((1 2) (3 4)))
<1,2> <3,4>
但现在我有一个缺点列表,例如((1 . 2) (3 . 4))
和表达式
(format t "~:{<~A,~A> ~}~%" '((1 . 2) (3 . 4)))
导致 SBCL 投诉
The value
2
is not of type
LIST
是否有任何 format
魔术可以在不使用 do
或 loop
的额外迭代的情况下实现这一目的?
我基本上看到了 4 个选项
不要对整个列表使用格式
直接的解决方法是避免问题:
(loop
for (k . v) in '((1 . 2) (3 . 4))
do (format t "<~a,~a> " k v))
自定义格式功能
或者,使用 Tilde Slash 调用打印 cons-cells 的函数:
(defun cl-user::pp-cons (stream cons colonp atsignp)
(declare (ignore colonp atsignp))
(format stream "~a, ~a" (car cons) (cdr cons)))
(format nil "~/pp-cons/" (cons 1 2))
=> "1, 2"
请注意,如果您不指定包,则该函数必须在 CL-USER 包中。如果要自定义单元格的打印方式,需要通过特殊变量传递格式:
(defvar *fmt* "(~s . ~s)")
(defun cl-user::pp-cons (stream cons colonp atsignp)
(declare (ignore colonp atsignp))
(format stream *fmt* (car cons) (cdr cons)))
然后:
(let ((*fmt* "< ~a | ~a >"))
(format t "~/pp-cons/" (cons 1 2)))
=> < 1 | 2 >
打印时转换
构建一个新列表,其中不正确的列表被正确的列表替换:
(format t
"~:{<~a,~a> ~}~%"
(series:collect 'list
(series:mapping (((k v) (series:scan-alist '((1 . 2) (3 . 4)))))
(list k v))))
缺点是转换需要分配内存,只是为了打印。
更改数据格式
如果适当的列表适合打印,也许它们也适合其他操作。许多标准函数都需要适当的列表。请注意,列表 ((1 2) (3 4))
仍然是一个列表,值只是包装在一个 cons-cell 中。如果您决定从一开始就使用这种格式,则无需转换您的列表。