Week 6 Day 1 – Feeling my way in Clojure

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! :)

Advertisements