Charlie Harvey

Clojure — Day Two

Today’s excercises seemed a little more straightforward than in previous languages. I may be simply getting brainier, of course. I doubt that.

It is something of a lightning tour that we take through Clojure; a lot of stuff gets covered in a little time. The chapter covers recursion, including how to do tail recursion; sequences; lazy evaluation; the defrecord and protocol approach to implementing types for the JVM and macros. Enough to keep me scratching my head for a while. Though it was mostly due to wrongly parentheses, the headscratching. Let’s have a look at the homework anyhow.


Implement an unless with an else condition using macros.

This seemed straightforward and took all of five minutes. After typing mine up I had a browse round some bloggers who had had a crack and found a much nicer solution by yannick. Yannick’s version makes the otherwise bit optional. For mine the else is compulsory. Not as cool. (defmacro unless [test body otherwise] (list 'if (list 'not test) body otherwise))

We'd best check that everything works as expected. user=> (unless false (println "true") (println ("false"))) true nil user=> (unless true (println "false") (println "true") ) true nil user=> (unless true (println "true") (println "false")) false nil user=> (macroexpand '(unless condition body alt-body)) (if (not condition) body alt-body) user=> Super. Excercise one done.


You can implement something like a Java class — a type in Clojure parlence — using the defrecord function. This is complemented by an equivalent of an interface, known as a protocol which your types may implement. I found this part of Clojure a bit fiddly, most likely as I’m just getting my head around the Clojure way. I can see a few ways where I may have avoided reusing code in my answer if only I knew the Clojure lingo.

Write a type using a defrecord that implements a protocol

I struggled with parentheses a little when working this out. It isn’t the most original class to choose I’m afraid. But it serves my purpose adequately. (defprotocol Animal (legs [num_legs]) (noise [sound]) (food [eats]) (eat [food]) ; idiomatic way to name variabls? ) (defn make_noise [noisemaker noise] (str noisemaker " says " noise) ) (defn munch [diner food] (str diner " munches on " food) ) (defrecord Kitten [name] Animal (legs [_] 4 ) (noise [this] (make_noise (:name this) "meee-owww") ) (food [_] "mouse") (eat [this] (munch (:name this) (food this) )) ) (defrecord Chicken [name] Animal (legs [_] 2 ) (noise [this] (make_noise (:name this) "cluck") ) (food [_] "corn") (eat [this] (munch (:name this) (food this) )) ) (def kitteh (Kitten. "Kitteh")) (def camilla (Chicken. "Camilla")) (println (noise kitteh) ) (println (legs kitteh) ) (println (food kitteh)) (println (eat kitteh)) (println (noise camilla) ) (println (legs camilla) ) (println (food camilla) ) (println (eat camilla))

OK cool, let’s just see what that does then. $ java -cp /usr/share/java/clojure.jar clojure.main protocol_record.clj Kitteh says meee-owww 4 mouse Kitteh munches on mouse Camilla says cluck 2 corn Camilla munches on corn

End of day two

And with that day two is over. I rather enjoyed Clojure’ 's simplicity. I found types a little fiddly, and I’ve ben havingfun with my VimClojure environment. The main VimClojure irritation is its smart parenthesizing. I really must consult the manual and find out how to delete unwanted parentheses. In fact that’d be one of my annoyances with Clojure. Of course the Lisp mystics will claim that you only see the parens when they aren’t right. But it’ll take some time for me to get to that stage. A whole heap of time.


  • You can use strong, em, code, pre, q and a HTML tags.
  • Comment and email are the only required fields.
  • Be respectful. You may want to read the comment guidelines before posting.

Privacy note: This form will forward your IP address, user agent and referrer to the Akismet, StopForumSpam and Botscout spam filtering services. I don’t log these details. Those services will. I do log everything you type into the form. Full privacy statement.