его элегантность снова сияет - Спасибо @Sylwester!
инарной книге Эди Вейц, для питоников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)
, Если представление сеп"#\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 !! Он решил это без макроса. И очень элегантно!