Clojure: a beginner’s notes

6 min read Original article ↗

I started learning Clojure earlier this year because I had heard that it was simple and beautiful and that learning Lisp was a mind-expanding thing to do. In no particular order, here are some of my observations:

For context, my day job is as a Rails developer.

You can’t just muddle through

When learning other languages I’ve found that learning the syntax for methods, iteration etc is usually enough to be dangerous. Not so in Clojure, where you have to learn the concepts. Some things are extremely awkward if not impossible if you don’t have a clue about partial, zipmap, interleave, drop , union and other things which you might have merrily ignored in eg Ruby.

I am half-expecting enlightenment

Every time I sit down to write some Clojure I hope in a small way that I am about to have some sort of transcendental experience brought on by the elegance of it all. This hasn’t happened yet, but I have thought that things were quite cool.

I do not know if the things I thought were cool are the things that others consider to be elegant about Clojure. I wonder what those things are.

4Clojure is great

But even some of the problems marked Easy are hard. The solutions are often more or less mind-blowing. I am glad I ran through as many of these as I did before I tried to implement anything. I recommend following dzholev.

Please don’t make me use emacs

I’m a vim user. I installed vim-fireplace and vim-sexp, and things seem kind of ok. I can’t help but wonder what I’m missing out on from emacs. I am good at vim, but I find it fairly horrible to edit s-expressions in it, even with vim-surround.

The REPL is convenient

For example:

  1. Write function and use vim-fireplace to evaluate it in the REPL.
  2. Invoke function from REPL, revealing unexpected behaviour
  3. Change function and re-evaluate it.
  4. Press up in the REPL and run it again, yielding different results.

This is great! However,

The REPL is difficult and/or confusing

Your code might not have state, but the REPL does, and I find it difficult to manage. I’d run a test from Vim and I couldn’t be sure if the result was a pass or false positive, because I couldn’t be sure which version of the function I was testing I’d last evaluated. Super confusing!

You build programs bit by bit

My first Clojure program is a data model for a Rubik’s cube. My approach has been to roughly chop up the processing into functions, try to write them and unit test them, find they do too much (or too little), chop up again and repeat. I’ve ended up with a handful of well-tested low-level functions that operate on little parts of the cube (ie the mini-cubes) and a layer of hardly-tested higher-level functions that operate on whole sections (rows, columns etc) of the cube.

I haven’t tested those much because tests for big data structures are hard to fit on one page and in my head. Also, I have a reasonable amount of confidence that if I map over a function I have tested to death, I don’t need to worry about that working—as long as I got the syntax for that higher-level function right. I wonder if this is what functional programming feels like.

I like the feeling that if I can trust my little functions, the big functions will do the right thing.

The approach I’m taking after writing a bit of Clojure

If I have a choice between writing a function that operates on a set of things and a function that operates on an individual thing from that set, I’ll choose the latter because it is much easier to reuse.

Functions are either doers or gluers. Doers do things like filtering, transforming and updating. Gluers call ->mappartialapply etc to link doers together. Doers are words, gluers are sentences.

Functions that take params plus a data structure to work on like to take the data structure as their last argument, so they can be partially applied.

Running tests with lein test is not an option

lein is amazingly slow! On my laptop it takes over 30 seconds to load and about 10 ms to run the tests. The solution seems to be to run the tests from your editor (but then you contend with state in the REPL).

You will be writing SQL by hand

Coming from Rails, I was amazed to discover that Luminus, which is as far as I can tell the pre-eminent web framework for Clojure, expects you to write your SQL queries by hand. By hand!

Composition over… everything else

Luminus is not so much a framework as a collection of libraries that provide the bones of an application, and once it’s installed you’re on your own with regard to how you organise your code. It’s closer to express.js than any of the “proper” MVC frameworks. There is nothing wrong with this but it’s a bit daunting for a beginner, especially one who is a bit worried about code organisation and namespaces.

Namespaces

Coming from Ruby, I’m almost inclined to treat namespaces a like classes and group functions that operate on the same data structure in them. But I suspect I’m just being set in my object-orientated ways. Another idea is to group functions that do the same sort of thing (eg printing functions, transforming functions, filtering functions, etc), but I wonder if that will end up with large namespaces full of functions, which I’d then split up into groups, and end up with an explosion of subdirectories and small files. Maybe that isn’t so bad .

I haven’t found that requiring namespace A inside namespace B and then requiring namespace B in namespace C means namespace A is available in namespace C. I am probably missing something here.

Must you already appreciate mathematics to appreciate Clojure?

I am bit worried the famous simplicity of the language is not the kind of simplicity I consider to be simple.

I suppose I’ll find out.

Unknown's avatar

Published by Duncan Brown

I am a Ruby developer at dxw, a public-sector-only technology agency in London. I am also the publisher of The Browser, a daily newsletter of interesting things.

Published