James Gunn
James Gunn

Reputation: 389

Printing a list with infix notation

I would like to convert an s-expression into a string with infix notation using format. How can this be done using format?

Example;

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

Upvotes: 3

Views: 141

Answers (4)

coredump
coredump

Reputation: 38809

This answer contains bad code.

Easy, just use custom formatters:

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

They are defined as follows:

(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)))

For example:

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

The memory variable is in the lexical scope of both functions, which allow them to communicate data. The first one stores the list, the second one uses it. If you never call the second function (or the first with nil), memory is forever bound to the last list, that could be a problem. Note also that you could have concurrency issues. Frankly, this is not the best possible way to do what you want , but it gets the job done w.r.t. your requirements.

Upvotes: 7

James Gunn
James Gunn

Reputation: 389

Here is the solution I have come up with.

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

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

=> "1 * 2 * 3"

Upvotes: 1

Ehvince
Ehvince

Reputation: 18375

With the str library*:

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

This join function is defined like so:

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

* unshamed promotion.

Upvotes: 4

Gwang-Jin Kim
Gwang-Jin Kim

Reputation: 9865

(format t "~{~A~^ * ~}" '(1 2 3))
;; 1 * 2 * 3
;; NIL
  • ~{~}: Loop over list.
  • ~A: Print human-readable (aesthetic)
  • ~^: Print the following only if there is a successor element in list.
  • *: Infix with surrounding empty spaces.

I was once asking a similar question. You added '* at the end - so you want also control over which separator should join the list elements. Look in the following link - @Sylwester gave the accepted answer: Nicer pythonic `join` in common-lisp .

(He did it by injection of a second format expression into a format expression - very elegant! - So that one can call (join '(1 2 3) :sep " * ")).

Upvotes: 5

Related Questions