Saturday, July 01, 2006

Always another way...

I finally gave the LOOP for Black Belts chapter in Practical Common Lisp a read. As such I started playing with loops.

I decided to do a quick test. One using mapcar and one using loop. The goal was to turn numeric values from 1-6 into string values containing the numbers 1-6.
'(1 2 3 4 5 6)
into
'("1" "2" "3" "4" "5" "6")

I first tried with mapcar:
(mapcar (lambda (x) (format nil "~a" x)) '(1 2 3 4 5 6))

Then with loop:
(loop for i in '(1 2 3 4 5 6) collect (format nil "~a" i))

Both get the exact same thing done, but there is a difference. Mapcar doesn't expand with macroexpand-1. However, when you try to expand the loop you get this:
(MACROLET ((LOOP-FINISH NIL (SYSTEM::LOOP-FINISH-ERROR)))
(BLOCK NIL
(LET ((#:G13088 '(1 2 3 4 5 6)))
(PROGN
(LET ((I NIL))
(LET ((#:ACCULIST-VAR-13089 NIL))
(MACROLET ((LOOP-FINISH NIL '(GO SYSTEM::END-LOOP)))
(TAGBODY SYSTEM::BEGIN-LOOP (WHEN (ENDP #:G13088) (LOOP-FINISH))
(SETQ I (CAR #:G13088))
(PROGN
(SETQ #:ACCULIST-VAR-13089
(CONS (FORMAT NIL "~a" I) #:ACCULIST-VAR-13089)))
(PSETQ #:G13088 (CDR #:G13088)) (GO SYSTEM::BEGIN-LOOP)
SYSTEM::END-LOOP
(MACROLET
((LOOP-FINISH NIL (SYSTEM::LOOP-FINISH-WARN) '(GO SYSTEM::END-LOOP)))
(RETURN-FROM NIL
(SYSTEM::LIST-NREVERSE #:ACCULIST-VAR-13089))))))))))) ;


Loop may be easier to read, but mapcar probably executes less code to get it done. One other difference is that loop doesn't need to use a lambda. I'll have to think about that next time I just want to iterate through a list.

Shaun

1 comment:

Zach Beane said...

MAPCAR is a function, LOOP is a (complicated) macro.

(mapcar #'princ-to-string '(1 2 3 4 5 6)) would avoid the lambda with mapcar.