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
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
Please don’t make me use emacs
I’m a vim user. I installed
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
The REPL is convenient
- Write function and use
vim-fireplaceto evaluate it in the REPL.
- Invoke function from REPL, revealing unexpected behaviour
- Change function and re-evaluate it.
- 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
apply 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.
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
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.