Common lisp 正在查找允许对列表进行自定义格式设置的格式字符串
我有一些列表,如下所示:Common lisp 正在查找允许对列表进行自定义格式设置的格式字符串,common-lisp,Common Lisp,我有一些列表,如下所示: CL-USER> (let ((std-function (pprint-dispatch 'cons))) (unwind-protect (progn (set-pprint-dispatch 'cons (lambda (s o) (format s "~d/~d" (car o) (
CL-USER> (let ((std-function (pprint-dispatch 'cons)))
(unwind-protect
(progn (set-pprint-dispatch
'cons
(lambda (s o) (format s "~d/~d" (car o) (cdr o))))
(format t "~{~a~%~}" '((23 . 24) (5 . 9))))
(set-pprint-dispatch 'cons std-function))
(format t "~{~a~%~}" '((23 . 24) (5 . 9))))
23/24
5/9
(23 . 24)
(5 . 9)
NIL
CL-USER>
((24.23)(9.6)…)
并希望自定义输出格式,如下所示:
CL-USER> (let ((std-function (pprint-dispatch 'cons)))
(unwind-protect
(progn (set-pprint-dispatch
'cons
(lambda (s o) (format s "~d/~d" (car o) (cdr o))))
(format t "~{~a~%~}" '((23 . 24) (5 . 9))))
(set-pprint-dispatch 'cons std-function))
(format t "~{~a~%~}" '((23 . 24) (5 . 9))))
23/24
5/9
(23 . 24)
(5 . 9)
NIL
CL-USER>
“24/23 9/6…”
我试过:
(defun show-pair (ostream pair col-used atsign-used)
(declare (ignore col-used atsign-used))
(format ostream "~d/~d" (first pair) (second pair)))
(let ((x '( 1 . 2))) (format nil "~{~/show-pair/~^~}" (list x)))
作为一个简单的热身练习,只需1对即可显示列表。但在emacs slime repl中尝试此操作时,我得到了错误
价值
2.
他不是那种人
列表
[类型错误的条件]
这当然令人困惑,因为
~/show pair/
需要处理列表中的一个条目,即pair,将pair传递给show pair
。但似乎还有其他事情正在发生。在等待反馈时,我发现了问题的根源:
到目前为止,我认为(second x)
的行为与(cdr x)
完全相同,但对于标记值,这种假设是错误的。如果我在上面(问题中)相应地更改show pairs
,则一切正常
因此,这根本不是一个格式问题,~/foo~/
的工作方式也不令人惊讶
(defun show-pair (ostream pair col-used atsign-used)
(declare (ignore col-used atsign-used))
(format ostream "~d/~d" (first pair) (cdr pair))) ;; second -> cdr fixes the problem
在等待反馈时,我发现了问题的根源: 到目前为止,我认为
(second x)
的行为与(cdr x)
完全相同,但对于标记值,这种假设是错误的。如果我在上面(问题中)相应地更改show pairs
,则一切正常
因此,这根本不是一个格式问题,~/foo~/
的工作方式也不令人惊讶
(defun show-pair (ostream pair col-used atsign-used)
(declare (ignore col-used atsign-used))
(format ostream "~d/~d" (first pair) (cdr pair))) ;; second -> cdr fixes the problem
以我的经验来看,以
格式使用~/…/
很少是个好主意。最好是简单地将您拥有的列表转换为您需要的列表,然后直接进行处理。例如:
> (format t "~&~:{~D/~D~:^, ~}~%"
(mapcar (lambda (p)
(list (car p) (cdr p)))
'((1 . 2) (3 . 4))))
1/2, 3/4
nil
或者如果要使用循环
:
> (format t "~&~:{~D/~D~:^, ~}.~%"
(loop for (n . d) in '((1 . 2) (3 . 4))
collect (list n d)))
1/2, 3/4.
nil
与打印列表的I/O成本相比,转换列表的成本(和存储)可能非常小。根据我的经验,以格式使用~/…/
几乎不是一个好主意。最好是简单地将您拥有的列表转换为您需要的列表,然后直接进行处理。例如:
> (format t "~&~:{~D/~D~:^, ~}~%"
(mapcar (lambda (p)
(list (car p) (cdr p)))
'((1 . 2) (3 . 4))))
1/2, 3/4
nil
或者如果要使用循环
:
> (format t "~&~:{~D/~D~:^, ~}.~%"
(loop for (n . d) in '((1 . 2) (3 . 4))
collect (list n d)))
1/2, 3/4.
nil
与打印列表的I/O成本相比,转换列表的成本(和存储)可能非常小。使用来自的提示,您可能会得到如下结果:
CL-USER> (let ((std-function (pprint-dispatch 'cons)))
(unwind-protect
(progn (set-pprint-dispatch
'cons
(lambda (s o) (format s "~d/~d" (car o) (cdr o))))
(format t "~{~a~%~}" '((23 . 24) (5 . 9))))
(set-pprint-dispatch 'cons std-function))
(format t "~{~a~%~}" '((23 . 24) (5 . 9))))
23/24
5/9
(23 . 24)
(5 . 9)
NIL
CL-USER>
隐藏簿记
(defmacro with-fractional-conses (&body body)
(let ((std-function (gensym "std-function")))
`(let ((,std-function (pprint-dispatch 'cons)))
(unwind-protect
(progn (set-pprint-dispatch
'cons
(lambda (s o) (format s "~d/~d"
(car o)
(cdr o))))
,@body)
(set-pprint-dispatch 'cons ,std-function)))))
CL-USER> (with-fractional-conses
(format t "~{~a~%~}"
'((23 . 24) (5 . 9))))
23/24
5/9
NIL
CL-USER>
使用来自的提示,您可能会得到如下结果:
CL-USER> (let ((std-function (pprint-dispatch 'cons)))
(unwind-protect
(progn (set-pprint-dispatch
'cons
(lambda (s o) (format s "~d/~d" (car o) (cdr o))))
(format t "~{~a~%~}" '((23 . 24) (5 . 9))))
(set-pprint-dispatch 'cons std-function))
(format t "~{~a~%~}" '((23 . 24) (5 . 9))))
23/24
5/9
(23 . 24)
(5 . 9)
NIL
CL-USER>
隐藏簿记
(defmacro with-fractional-conses (&body body)
(let ((std-function (gensym "std-function")))
`(let ((,std-function (pprint-dispatch 'cons)))
(unwind-protect
(progn (set-pprint-dispatch
'cons
(lambda (s o) (format s "~d/~d"
(car o)
(cdr o))))
,@body)
(set-pprint-dispatch 'cons ,std-function)))))
CL-USER> (with-fractional-conses
(format t "~{~a~%~}"
'((23 . 24) (5 . 9))))
23/24
5/9
NIL
CL-USER>
如果要使用格式
-问题是使用格式
指令访问列表的第一个和第二个元素。我没有找到如何在格式
指令中访问它们
然而,在像alist这样的规则结构中,可以先将列表展平,然后让format
-循环指令在每个循环中消耗两个元素,然后一个消耗这对元素
由于著名的:alexandria
库在Common Lisp世界中不算作依赖项,因此可以直接使用alexandria:flatte
:
(defparameter *al* '((24 . 23) (9 . 6)))
(ql:quickload :alexandria) ;; import alexandria library
(format nil "~{~a/~a~^ ~}" (alexandria:flatten *al*))
;; => "24/23 9/6"
nil
作为字符串返回
~{}
在列表上循环
~a/~a
分数
~^
元素之间的空格,但不能在最后一个元素之后
展平
顺便说一句,没有:alexandria
-“依赖性”在这种情况下是:
(defun flatten (l)
(cond ((null l) nil)
((atom l) (list l))
(t (append (flatten (car l)) (flatten (cdr l))))))
如果要使用格式
-问题是使用格式
指令访问列表的第一个和第二个元素。我没有找到如何在格式
指令中访问它们
然而,在像alist这样的规则结构中,可以先将列表展平,然后让format
-循环指令在每个循环中消耗两个元素,然后一个消耗这对元素
由于著名的:alexandria
库在Common Lisp世界中不算作依赖项,因此可以直接使用alexandria:flatte
:
(defparameter *al* '((24 . 23) (9 . 6)))
(ql:quickload :alexandria) ;; import alexandria library
(format nil "~{~a/~a~^ ~}" (alexandria:flatten *al*))
;; => "24/23 9/6"
nil
作为字符串返回
~{}
在列表上循环
~a/~a
分数
~^
元素之间的空格,但不能在最后一个元素之后
展平
顺便说一句,没有:alexandria
-“依赖性”在这种情况下是:
(defun flatten (l)
(cond ((null l) nil)
((atom l) (list l))
(t (append (flatten (car l)) (flatten (cdr l))))))
second
的行为从来不像cdr
;cdr
的同义词是rest
。每当一个人使用其他的、新的东西并专注于这些东西时,就会发生这种愚蠢的错误(就像我第一次使用这种格式)。second
的行为从来不像cdr
;cdr
同义词是rest
。每当一个人使用其他新事物并关注这些事物时,就会发生类似的愚蠢错误(就像我第一次使用这种格式)。这(v1)是一种相当危险的方法,因为它本质上是对调度表的浅绑定(实际上:它是表中的浅绑定条目),而浅层绑定很难保证线程安全,在这种情况下肯定不会。更好的方法是创建表的副本,然后显式地将*print pprint dispatch*
绑定到该副本。然而,这是一个聪明的把戏!这(v1)是一种相当危险的方法,因为它本质上是对分派表的浅绑定(实际上:它是表中的浅绑定条目),而浅绑定很难保证线程安全,在这种情况下肯定不会。更好的方法是创建表的副本,然后显式地将*print pprint dispatch*
绑定到该副本。然而,这是一个聪明的把戏!是的,我也考虑过这个想法,但我的真实数据有时超过2个元素,有时是数字,有时是符号。