Thursday, December 11, 2008

Lazy Lists are awesome

Okay, first off, Clojure's seq abstraction is awesome. This lets you take anything that can be turned into a list-like thing (vectors, Java iterables, maps, whatever) and iterate over it like a list. This means that all the functions that deal with lists (map, filter, so forth) work on everything else. Super cool.

One of the things you can treat like any other seq in Clojure is a lazy list. You can think of this as a generator if you're from C# or Python or such, and you wouldn't be too far off. What it is conceptually is a list in which every element is generated just in time when you ask for it. You give the first item in the list (grabbed by clojure's "first" function) and a function which, when called, returns the rest of the list. The rest of the list is one item and (you guessed it) a function which, when called, returns the rest of the list. Wow, I just felt some deja-vu...

Here's an example - the list of all the fibonnaci numbers. No, really.

(defn make-fibonacci-seq []
"returns an lazy, infinite seq of the fibonacci numbers"
((fn next-fib [one two]
(lazy-cons one (next-fib two (+ one two))))
1 1))

(def fibonacci-numbers (make-fibonacci-seq))

(take 10 fibonacci-numbers) => (1 1 2 3 5 8 13 21 34 55)


Yeah. Sweet. lazy-cons is a macro that does the value-and-function magic I mentioned above. Ah, macros. Ah, lisp. Ah, clojure!

No comments:

Post a Comment