Lisp форматирование строк с именованными параметрами

Есть ли способ в Lisp форматировать строку, используя именованные параметры?

Возможно, что-то со списками ассоциаций, например

(format t "All for ~(who)a and ~(who)a for all!~%" ((who . "one")))

чтобы напечатать "All for one and one for all".

Аналогично этот вопрос python или этот scala один или даже С++, но в Lisp.

Если эта функциональность отсутствует в языке, есть ли у кого-нибудь какие-нибудь интересные функции или макросы, которые могут выполнить одно и то же?

Ответ 1

Используйте CL-INTERPOL.

(cl-interpol:enable-interpol-syntax)

Строковая интерполяция

Для простых случаев вам не нужно FORMAT:

(lambda (who) #?"All for $(who) and $(who) for all!")

Тогда:

(funcall * "one")
=> "All for one and one for all!"

Директивы формата интерпретации

Если вам нужно отформатировать, вы можете сделать:

(setf cl-interpol:*interpolate-format-directives* t)

Например, это выражение:

(let ((who "one"))
  (princ #?"All for ~A(who) and ~S(who) for all!~%"))

... prints:

All for one and "one" for all!

Если вам интересно, вышесказанное читается как:

(LET ((WHO "one"))
  (PRINC
    (WITH-OUTPUT-TO-STRING (#:G1177)
      (WRITE-STRING "All for " #:G1177)
      (FORMAT #:G1177 "~A" (PROGN WHO))
      (WRITE-STRING " and " #:G1177)
      (FORMAT #:G1177 "~S" (PROGN WHO))
      (WRITE-STRING " for all!" #:G1177))))

Альтернативная функция чтения

Ранее я глобально устанавливал *interpolate-format-directives*, который интерпретирует директиву формата во всех интерполированных строках. Если вы хотите точно контролировать, когда форматированные директивы интерполируются, вы не можете просто временно привязать переменную в своем коде, потому что магия происходит во время чтения. Вместо этого вы должны использовать пользовательскую функцию чтения.

(set-dispatch-macro-character
 #\#
 #\F
 (lambda (&rest args)
   (let ((cl-interpol:*interpolate-format-directives* t))
     (apply #'cl-interpol:interpol-reader args))))

Если я reset специальная переменная имеет значение по умолчанию NIL, то строки, в которых форматируются директивы, имеют префикс #F, тогда как обычные интерполированные используют синтаксис #?. Если вы хотите изменить readtables, посмотрите named readtables.