Sunday, 7 December 2008

Five minutes with Clojure

After setting things up I had a spare five minutes to actually try some Clojure. Most frustrating thing so far is the lack of decent error messages. For example, getting messages like below isn't that helpful to me at the moment!

java.lang.IllegalArgumentException: Don't know how to create ISeq from: Integer (NO_SOURCE_FILE:1)
[Thrown class clojure.lang.Compiler$CompilerException]

0: [ABORT] Return to SLIME's top level.
1: [CAUSE] Throw cause of this exception

;;; snip

First class support for more data structures than Lisp is great. There's Set, Map and Vector represented by the syntax below.

'(a b c) ; list
['a 'b 'c] ; vector
{:a 1 :b 2 :c 3} ; map
#{:a :b :c} ; set

I'm still a little confused with some of the syntax, for example with the latest version from SVN the following happens

'(a b c) ==> (a b c)
('a 'b 'c) ==> c

Odd. Wonder why that is? a is a symbol bound to a function that apparently returns its first or second argument if it has 1 or 2 args. It's not defined for more arguments. Weird.

For declaring functions, you don't use defun. Instead you can use fn to create a function, for example (shamelessly stolen from Practical Common Lisp)

(def make-cd (fn [title artist rating] (list title artist rating)))
(make-cd "Technology Sucks" "AC" 1) ==> ("Technology Sucks" "AC" 1)

You can simplify the above definition using the defn macro.

(defn make-cd [title artist rating] (list title artist rating))

macroexpand-1 shows that this expands into the above. defn allows you to provide some overloads. I couldn't think of a good example, but the syntax is pretty simple, just a list of forms.

(defn crazy-function
([x] (list 42))
([x y] (list (+ x y)))
([x y &more] (list y)))

(crazy-function 7) ==> 42
(crazy-function 7 11) ==> 18
(crazy-function 1 2 3 4 5) ==> 2