В кулинарной книге Эди Вейц, для pythonic join
, предлагается эта функция:
(defun join (separator list)
(with-output-to-string (out)
(loop for (element . more) on list
do (princ element out)
when more
do (princ separator out))))
Однако, как-то я думал, что должен быть способ выразить join
по-другому, возможно, используя возможности format
...
В книге Сейбеля (в главе о format
) мы находим соединение строк в списке в одну строку с разделителем ", "
с помощью:
(defvar l '("a" "b" "c"))
(format nil "~{~A~^, ~}" l)
;; "a, b, c"
Который является питоническим соединением и который очень краткий;директива ~^
означает, что ", "
добавляется только до последнего элемента и не добавляется, когда ни один элемент не следует за ним.
Однако здесь разделительная строка ", "
является частью директивы формата.
Хитрый случай, например (defvar sep #\Tab)
.Если представление sep "#\Tab"
буквально можно поместить в качестве разделителя в середине этой директивы формата, в результате чего:
(format nil "~{~A~^#\Tab~}" l)
Мы бы достигли цели.
Очевидно, одиндолжен использовать макрос для генерации директивы формата ... Я пробовал что-то вроде (princ-to-string sep)
, но это дает "#\\Tab"
, а не "#\Tab"
.
Например
(defmacro join (sep l)
`(format nil ,(format nil "~{~A~}" `("\~\{\~A\~\^" ,(write-to-string sep) "\~\}")) l))
Но когдапытаясь:
(join #\Tab '("a" "b" "c"))
Этот результат, конечно, не желателен: "a#\\Tabb#\\Tabc"
, так как
(macroexpand-1 '(join #\Tab '("a" "b" "c")))
;; results in:
(FORMAT NIL "~{~A~^#\\Tab~}" L)
;; instead of:
(FORMAT NIL "~{~A~^#\Tab~}" L)
Но я не вижу, как достичь этого шага для нужного макроса... У кого-нибудь есть понимание по этому поводу?
Вроде метапрограммирования по проблеме метапрограммирования ...
Хорошо, теперь я вижу, что @Rainer Joswig уже опубликовал в Что заканонический способ объединения строк в список?
решение этой проблемы.Однако, если бы был способ представить "#\\Tab"
как "#\Tab"
, можно прийти к более компактному определению.Но почему-то читатель Lisp кажется в строке всегда распознающей "\Tab"
как одну букву.Можно ли написать функцию для этого?
Примечание
В R специально для метапрограммирования существуют такие функции, как as.name("myvar")
, которые генерируют символ myvar
из строки "myvar".и выражения типа deparse(substitute(x))
, который принимает символ x
и создает из него буквальную строку "x"
.Deparse возвращает назад выполнение print()
команд, в результате чего экранируются специальные символы.deparse(deparse(substitute(x)))
будет, например, генерировать "\"x\""
- в то время как parse(text = ... )
вокруг этого выражения сделает из него "x"
снова parse(text = deparse(deparse(substitute(x))))
.Как такие вещи могут быть достигнуты в Common-Lisp?например, (a-special-function #\Tab)
в результате (буквально): "#\Tab"
в виде строки?
Эпилог
Спасибо @Sylwester !!Он решил это без макроса.И очень элегантно!