Печать списка с инфиксной нотацией - PullRequest
3 голосов
/ 13 июня 2019

Я хотел бы преобразовать s-выражение в строку с инфиксной нотацией, используя format. Как это можно сделать, используя format?

Пример;

(format t "<insert format controls here>" (1 2 3) '*)
=> "1 * 2 * 3"

Ответы [ 4 ]

7 голосов
/ 13 июня 2019

Этот ответ содержит неверный код.

Легко, просто используйте пользовательские средства форматирования :

(format t "~/acquire/~/disseminate/" '(1 2 3) '*)

Они определены следующим образом:

(let ((memory))
  (defun cl-user::acquire (stream list &optional colonp atsignp)
    (declare (ignore colonp atsignp stream))
    (setf memory list))
  (defun cl-user::disseminate (stream operator &optional colonp atsignp)
    (declare (ignore colonp atsignp))
    (format stream (concatenate 'string "~{~a~^ " (string operator) " ~}") memory)
    (setf memory nil)))

Например:

CL-USER> (format t "~/acquire/~/disseminate/" '(1 2 3) '*)
1 * 2 * 3

Переменная memory входит в лексическую область обеих функций, которые позволяют им передавать данные.Первый хранит список, второй использует его.Если вы никогда не вызовете вторую функцию (или первую с нулем), memory означает навсегда для последнего списка, это может быть проблемой.Обратите внимание, что у вас могут возникнуть проблемы с параллелизмом. Честно говоря, это не самый лучший способ сделать то, что вы хотите , но он выполняет работу в соответствии с вашими требованиями.

5 голосов
/ 13 июня 2019
(format t "~{~A~^ * ~}" '(1 2 3))
;; 1 * 2 * 3
;; NIL
  • ~{~}: зацикливание списка.
  • ~A: печать, удобочитаемая ( a , эстетическая)
  • ~^: Выведите следующее, только если в списке есть элемент-преемник.
  • *: Инфикс с окружающими пустыми пробелами.

Однажды я задавал подобный вопрос.Вы добавили '* в конце - поэтому вы также хотите контролировать, какой разделитель должен join элементов списка.Посмотрите на следующую ссылку - @Sylwester дал принятый ответ: Более приятное pythonic `join` в common-lisp .

(Он сделал это путем введения выражения второго формата в выражение формата- очень элегантно! - чтобы можно было звонить (join '(1 2 3) :sep " * ")).

4 голосов
/ 14 июня 2019

С библиотекой str *:

(str:join " * " '(1 2 3))
;; "1 * 2 * 3"

Эта join функция определена так:

(defun join (separator strings)
  (let ((separator (replace-all "~" "~~" separator)))
    (format nil
            (concatenate 'string "~{~a~^" separator "~}")
            strings)))

* безупречное продвижение.

1 голос
/ 13 июня 2019

Вот решение, которое я придумала.

(defun compile-arith (expr)
  (format nil (concatenate 'string "~{~(~a~)~^ " (string (car expr)) " ~}")
    (cdr expr)))

(compile-arith '(* 1 2 3))

=> "1 * 2 * 3"
...