Wednesday, February 21, 2007

More than List Comprehensions. Common Lisp Loop

Now, here I was admiring list comprehensions in other languages but lisp. It seams the loop macro is more than it looks. List comprehensions are an iterative style combination of map and filter constructs. Well, with loop in lisp you can do even more. You can actually include reduce in the picture.

A helper macro to shorten our code ;) :

(defmacro for(&body body)
    `(loop for ,@body))

A small function builder that integrates reduce into loop:

(defun loop-reduce (fn)
    (lambda (l)
        (when (cdr l)
            (cons (funcall fn (car l) (cadr l))
                        (cddr l)))))

Here are the basic implementations of these three function in the loop sub-language:

Two nested maps (applied function is list):

(for x below 3 nconc
    (for y below 3 collect
        (list x y)))

and the result:
((0 0) (0 1) (0 2) (1 0) (1 1) (1 2) (2 0) (2 1) (2 2))

A simple filter (applied function is oddp):

(for x below 10 when (oddp x) collect x)

with the result:
(1 3 5 7 9)

And finally a reduce (applied function is +):

(for x in '(1 2 3 4) by (loop-reduce #'+) finally (return x))

with the result:

If you do:

(for x in '(1 2 3 4) by (loop-reduce #'+) collect x)

you also get the intermediary results:
(1 3 6 10)

Well, the last reduce could have been a lot easier written as:
(for x in '(1 2 3 4) sum x)
but this isn't that general (even if it works also with counting, minimizing, maximizing).

Now, isn't that nice :P


Anonymous said...

the formating of the code examples sucks.

subpic said...

fixed ?