So i am starting to learn a bit of Clojure. It’s not completely alien to me because i’ve done a little bit of SICP with Scheme, another variant of Lisp. The syntax seems quite logical to me, and i like its simplicity.
At the moment we seem to be running everything within the console rather than writing to a file. So i’ll just paste what i’m learning in here.
Lists, Maps, Sets and Vectors
This is quite a lot to take on board. Let me see if i can distill it.
Lists and vectors are ordered. Sets and maps are unordered but can be sorted with the sort and sort-map functions, respectively.
Use lists for code and vectors for data. Vectors are optimized for random access. Maps are key-value pairs. Sets and maps are magically also functions, which to me seems really bizarre but powerful!
Functions
We define data with def and a functions with defn. I didn’t know that you can add an optional string for documentation of a function. That’s nice. Parameters go as a vector, and then it’s the body of the function.
There is a cool trick with destructuring the parameters: if you’re passed more than you actually need, you can pull out just the bits that you want to work with. I see similarities from Scala and Erlang pattern matching.
First exercise
Implement a function called (big st n) that returns true if a string st is longer than n characters.
(defn big [st n] (> (count st) n))
defn defines a function, the name is ‘big’, there are two parameters and we check whether the length of the first is greater than the second.
Second exercise
Write a function called (collection-type col) that returns :list, :map, or :vector based on the type of collection col.
First i tried this just to see what would happen:
(defn collection-type [col] (type col))
Actually something quite interesting happens:
user=> (collection-type '(:r2d2 :c3po))
clojure.lang.PersistentList
user=> (collection-type [:hutt :wookie :ewok])
clojure.lang.PersistentVector
user=> (collection-type {:darth-vader "obi wan", :luke "yoda"})
clojure.lang.PersistentArrayMap
I thought about doing a grep for the last word starting with a capital letter, lowercasing it, prefixing it with a colon … that would have been neat but it would also require clojure-contrib (community created extensions) which i couldn’t find out how to include.
So i’m not going to do that.
Fortunately there are shortcut functions we can use:
(defn collection-type [col] (vector? col))
This will return true if the collection given is a vector. There are similar functions for list? and map? so we can use some kind of test to see what we get.
I wanted some kind of if function that could take multiple options followed by results. The Clojure answer to that is a cond function.
And here it is (updated to close all the parentheses on one line as suggested by Tom):
(defn collection-type [col]
(cond
(list? col) :list
(vector? col) :vector
(map? col) :map))
I can learn to love parentheses! :)
Just a tiny note on usual syntax. Standard lisp style puts all of the closing parens together, so your last function should look like this:
(defn collection-type [col]
(cond
(list? col) :list
(vector? col) :vector
(map? col) :map))
oh, that’s cool! looks like haml, i can deal with that! :)
Instead of cond, think of using a map instead :)
oooh, thanks. i will try that out tonight.
I think you’ll like haskell pattern matching. I don’t really know how it compares to Scala and Erlang (ah, this 7languages thing is useful, isn’t it?) but it’s good.
I thought when I saw defn and def that it was a lisp-2 but I just looked it up and apparently not. http://hornbeck.wordpress.com/2009/07/05/lisp-1-vs-lisp-2/ I thought a lisp-1 would just use def like scheme.
yes, some kind of pattern matching has been a recurring theme in the book. as has higher order functions. it’s great to see the connections and differences.
What languages do you currently use for work? I’m coming into Clojure from a pure empirical background, so concepts like having a function return a vector of vectors is still a struggle. The Google Clojure group is pretty friendly and have helped me get over hurdles.
The only way I could learn Clojure was to design a small production project and implement it. That and a bug with embedded C code in Informix were incentive enough to start working more in Clojure.
Good luck.
I mostly program in Ruby at the moment. Thanks for recommending The Joy of Clojure.
You may find The Joy of Clojure to be useful – it’s a most excellent introduction to the language. http://joyofclojure.com/ – kind of unfortunate cover art, but the contents are first-rate.
Thank you for recommending it, that looks good!
Currently, I have three books, Programming Clojure, The Joy of Clojure, and Practical Clojure. This is a pretty high book count for me at this point ~2 mos in learning a new language — because usually one or two will get me through the learning stage. All three books present Clojure differently and interestingly, and in my opinion, all are well-written.
However, these books and most on-line material I have read do not bridge the empirical OO and non-OO language and functional programming language mindsets. Programming Clojure goes a along way to provide some guidelines on Clojure programming in The Six Rules of Clojure FP. Those are good starting rules, but still I’ve found nothing that says, for example, here is how Clojure treats a function that returns a structure, list, pointer, and so on.