views:

112

answers:

4

I'm beginning to write me some Common Lisp and am just getting the hang of consing things together and formatting them.

Let's suppose I have an alist, like this:

(defvar *map* '((0 . "zero") (1 . "one") (2 . "two")))

How do I format it like this?

0: zero
1: one
2: two

I was thinking something like (format t "~{~{~a: ~a~}~%~}" *map*), but that gives an error because "zero" isn't a list and you can't take the car of it.

Of course, doing (format t "~{~a~%~}" *map*) prints

(0 . "zero")
(1 . "one")
(2 . "two")

like it's supposed to, but it's not quite what I want. Is there a better way to do this than just (dolist (entry *mapping*) (format t "~a: ~a~%" (car entry) (cdr entry)))?

A: 

I don't think there's a better way to do it; I would used map():

(format t "~{~a~%~}"
  (map 'list
    #'(lambda (entry)
      (format nil "~a: ~a" (car entry) (cdr entry))
    *map*))
Adam Rosenfield
MAPCAR is more to the point...
skypher
+5  A: 

You're right, in that it doesn't look like there's any way to pick apart a cons cell from FORMAT.

If you define another function to format a single association:

(defun print-assoc (stream arg colonp atsignp)
  (format stream "~A: ~A" (car arg) (cdr arg)))

then it's easy:

(format t "~{~/print-assoc/~%~}" *map*)

I'm not sure if this is an improvement or not. On the one hand, it's a little more complex, but on the other hand, it does break out print-assoc into a (reusable) function, which could be useful.

Ken
You should use qualified function names in format. FORMAT parses the specified symbol in *package* and you will never know what is the *package* at the time the format is called.
dmitry_vk
+6  A: 

The #cl-gardeners channel on Freenode suggests doing a destructuring loop bind like this:

(loop for (a . b) in *mapping*
  do (format t "~a: ~a" a b))
Michael
+2  A: 

I think the takeaway lesson here is really not to use dotted lists for your alists. You save one cons cell, sure, but you give up all the nice sequence and list functions. It's just not worth it. Your formatting example is trivial with fully formed lists:

(defvar *map* '((0 "zero") (1 "one") (2 "two")))
(format t "~:{~a: ~a~}" *map*)
dlowe