Я вижу в основном 4 варианта
Не используйте формат для всего списка
Простое решение - избежать проблемы:
(loop
for (k . v) in '((1 . 2) (3 . 4))
do (format t "<~a,~a> " k v))
Функция пользовательского формата
В качестве альтернативы используйте Tilde Sla sh для вызова функции, которая печатает cons-ячейки:
(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 >
Конвертировать при печати
Создайте список fre sh, где неправильные списки заменяются правильными списками:
(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-ячейку. Если вы решите использовать этот формат с самого начала, вам не придется конвертировать списки.