Is there a format directive to iterate over vectors in Common Lisp?
common-lisp, format
Solution
(defun pprint-array (stream array
&optional colon amp (delimiter #\Space))
(declare (ignore colon amp))
(loop
:with first-time = t
:for x :across array
:unless first-time :do (format stream "~C" delimiter) :end
:do (format stream "~S" x)
(setf first-time nil)))
(format t "~' :@/pprint-array/" #(1 2 3 4)) ; 1 2 3 4
You can add more arguments (they would be separated by comma), or you could also handle somehow colon and ampersand.
Following Svante's advise here's a somewhat altered version of this function, it also utilizes the colon and ampersand in the following way: colon makes it alter between `prin1` and `princ` and at-sign makes it print nested arrays recursively (it could be further sophisticated to also print multidimensional arrays etc... but having limited time here's what it is:
(defun pprint-array (stream array
&optional colon amp
(delimiter #\Space) (line #\Newline))
(if amp (loop
:with first-time = t
:for a :across array
:unless first-time
:do (when line (write-char line stream)) :end
:if (or (typep a 'array) (typep a 'vector))
:do (pprint-array stream a colon amp delimiter line)
:else
:do (if colon (prin1 a stream) (princ a stream)) :end
:do (setf first-time nil))
(loop
:with first-time = t
:for x :across array
:unless first-time
:do (when delimiter (write-char delimiter stream)) :end
:do (if colon (prin1 x stream) (princ x stream))
(setf first-time nil))))
Problem
Common Lisp supports an plethora of formatting directives. However, I couldn't find a handy directive for my problem. Basically, I'd like to print a grid of numbers. Using a list the following works nicely: ``` (format t "~{~A|~A|~A~%~^-----~%~}" '(1 2 3 4 5 6 7 8 9)) 1|2|3 ----- 4|5|6 ----- 7|8|9 NIL ``` I was unable find a similar construct to iterate over vectors. CLtL2 states clearly that `~{...~}` expects a list as argument. I tried using a vector anyway, but my Clisp rightly exclaimed about the wrong argument type. As a workaround I convert the my vector into a throw-away list using the almighty `loop`. ``` (let ((lst (loop for e across '#(1 2 3 4 5 6 7 8 9) collecting e))) (format t "~{~A|~A|~A~%~^-----~%~}" lst)) 1|2|3 ----- 4|5|6 ----- 7|8|9 NIL ``` This works, but it strikes me as a clumsy makeshift solution. I'd rather not create tons of temporary lists only for `format`. Is there a way to iterate vectors directly? Out of curiosity, is there a reason why `format` shouldn't support sequences?