A Little More Clojure Enlightenment

If there’s one thing I’ve been thinking about all year, it’s tool-based thinking.  I’ve spent my time getting out of Visual Studio, getting out of .NET and smelling the flowers.  Turns out Vim is a great editor, Coffeescript is a great language and Clojure… still has a lot to teach me.  One of the odd things with Clojure is that there’s not many people writing about it.  I have a theory that this is basically because there’s not much to say.  It’s elegant and it works.

It is however, insanely expressive, which can lead to some rather entertaining debate as to the most elegant way to implement something.  This is one I asked on the Clojure IRC room:

(fn [f coll] (reduce #(assoc %1 %2 (f %2)) {} coll))

For those of you not familiar with Clojure, this takes a list and creates a map where the keys are the original list and the values are what you would get by applying f to the key.  This is pretty much the inverse of what “group-by” does.  If you read the source of group-by, you’ll notice that it uses a transient hashmap internally, which is faster than the naive implementation above.  Here’s two that were proposed:

(fn [f coll] (apply hash-map (mapcat (juxt identity f) coll)))

(fn [f coll] (zipmap coll (map f coll)))

Of the two, I prefer the second, because it involves constructing fewer intermediate objects.  For those of you interested in performance, you’ll be disappointed to learn that zipmap doesn’t use transients (yet).

It’s worth revisiting why I’d want such a function.  In C#, I’ll commonly pre-compute results of functions and throw them around in Dictionaries, and when translating to a functional language I just translated the behaviour.  (Yadic commits the same sin.)  So why does Clojure not have a built-in function for generating maps like this?  Basically, because memoize is more powerful, more flexible and doesn’t require you to know your keys beforehand.  In particular, it would be hard to distinguish between the first code example and

(fn [f coll] (memoize f))

For those of you not familiar with Clojure, this does rely on one of the neater syntax shortenings in Clojure: any map is a function that takes a key and returns the corresponding value or nil.

Published by

Julian Birch

Full time dad, does a bit of coding on the side.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s