Drew McDermott thinks format stinks. And he has an alternative.
He takes on what Guy Steele called “the hairiest format control string I have ever seen,” used for printing the xapping data types in Connection Machine Lisp:
---------------------------------------------------------------- Table 22-8: Print Function for the Xapping Data Type (defun print-xapping (xapping stream depth) (declare (ignore depth)) (format stream ;; Are you ready for this one? "~:[{~;[~]~:{~S~:[->~S~;~*~]~:^ ~}~:[~; ~]~ ~{~S->~^ ~}~:[~; ~]~[~*~;->~S~;->~*~]~:[}~;]~]" ;; Is that clear? (xectorp xapping) (do ((vp (xectorp xapping)) (sp (finite-part-is-xetp xapping)) (d (xapping-domain xapping) (cdr d)) (r (xapping-range xapping) (cdr r)) (z '() (cons (list (if vp (car r) (car d)) (or vp sp) (car r)) z))) ((null d) (reverse z))) (and (xapping-domain xapping) (or (xapping-exceptions xapping) (xapping-infinite xapping))) (xapping-exceptions xapping) (and (xapping-exceptions xapping) (xapping-infinite xapping)) (ecase (xapping-infinite xapping) ((nil) 0) (:constant 1) (:universal 2)) (xapping-default xapping) (xectorp xapping)))
Drew says “Folks, you don't have to put up with this nonsense. Here is the civilized way to write the print-function.”
(defun print-xapping (xapping stream depth) (declare (ignore depth)) (out (:to stream) ;; Print ``['' for a xector, and ``{'' otherwise. (:q ((xectorp xapping) "[") (t "{")) ;; Print the pairs implied by the xapping. ;; Whether the element to the left of the arrow comes from ;; the list 'd' or the list 'r' depends on whether the ;; xapping is a xector. An arrow is printed only if ;; xapping is not a xector or a xet. The element to the ;; right of the arrow always comes from 'r'. ;; Each pair is followed by a space, except the last. (:e (do ((vp (xectorp xapping)) (sp (finite-part-is-xetp xapping)) (d (xapping-domain xapping) (cdr d)) (r (xapping-range xapping) (cdr r))) ((null d)) (:o (if vp (car r) (car d)) (:q ((not (or vp sp)) "->")) (car r) (:q ((not (null (cdr d))) " "))))) ;; If there were pairs and there are exceptions or an infinite part, ;; print a separating space. (:q ((and (xapping-domain xapping) (or (xapping-exceptions xapping) (xapping-infinite xapping))) " ")) ;; Given a list of exception indices, print them. (:e (do ((el (xapping-exceptions xapping) (cdr el))) ((null el)) (:o (car el) (:q ((not (null (cdr el))) " "))))) ;; If there were exceptions and there is an infinite part, ;; print a separating space. (:q ((and (xapping-exceptions xapping) (xapping-infinite xapping)) " ")) ;; The infinite part is omitted if nil, printed as "->k" if it's a ;; constant k, and printed as "->" if it's "universal" (:e (ecase (xapping-infinite xapping) ((nil)) (:constant (:o "->" (xapping-default xapping))) (:universal (:o "->")))) ;; Print ``]'' for a xector, and ``}'' otherwise. (:q ((xectorp xapping) "]") (t "}"))))Posted by jjwiseman at November 18, 2005 12:20 PM
Looks like a good idea. Format is something nice for C programmers learning Lisp, but it never did feel very "lispy" to me. I guess I never really put too much thought into improving it, although it now seems like the obvious thing to do. I'm glad somebody had the idea.
Posted by: Benjamin on November 18, 2005 08:19 PMNot surprising that it doesn't feel "lispy": it was stolen directly from Multics' ioa_.
http://groups.google.com/group/comp.lang.lisp/msg/6d8759a0f7b8f460
So it actually predates Unix and C.
Posted by: ken on February 18, 2008 04:41 PM