Seven Languages in Seven Weeks Part 10: Clojure Day 1
by Justin Michalicek on May 8, 2011, 8:59 a.m. UTCSo I finished the Erlang chapter and have moved on to Clojure. Before I talk about Clojure I'll wrap up Erlang briefly. I'm not posting the Erlang Day 3 bits because they weren't terribly interesting. The first exercise was incredibly simple and was nearly a copy and paste of examples already given. The second I could find no way to do, no examples, etc. The third was basically copying the first again. The bonus exercises appeared to be too much dull boilerplate and configuration to bother with.
Clojure seems alright so far. Unfortunately I suspect I may spend as much time fighting with syntax as actually solving the logic of the problems, which is no fun. For anyone who is unaware, Clojure is a LISP dialect that runs on the JVM. This is interesting since it is a nearly purely functional language which has access to Java core classes. It uses prefix rather than infix style syntax, which means that operators come before things they are operating on. Functions are lists and so are enclosed in () which can make the syntax a bit difficult to parse although a proper editor of some sort rather than writing code in interactive shell would probably sort that out.
Anyway, on to the day one exercises. First off is creating a function which takes a string and an int parameter and returns true if the string has more characters than the int. I kept this pretty naive and so just assume the int parameter is actually an int and the string is a string since it was going to get a bit hard to read otherwise. Clojure does provide a way to check the class of a value, so you could make sure they are the correct classes before comparing them.
user=> (defn big [st n] (if (> (.length st) n) true)) #'user/big user=> (big "wheeee" 3) true user=> (big "whe" 3) nil
Yep, that's it, just that simple one liner above. You could actually shorten it up a bit. (> (.length st) n) actually returns a boolean, so you could just return that. The book said to return true if the length of st is great than n and did not say to return false if it is not, so I added the extra true on the end to ensure it only returns true and not false. You can see how I call Java's String.length by calling .length and then giving it the String to call it on.
The second exercise was to write a function that takes a list, vector, or map and returns :list, :vector, or :map respectively. This was pretty straightforward as there are functions for checking if a variable is a list, map, or vector. The only part that tripped me up initially is that the if statements had to be nested as if list / else if map / else if vector rather than just in a row as separate if statements. This is because the value of the last statement gets returned and there is no "return" to break out early. This caused the separate if statements to only return a value if the last one was true, otherwise the last statement executed was not true, so no value.
user=> (defn collectiontype [col] (if (list? col) :list (if (map? col) :map (if (vector? col) :vector)))) #'user/collectiontype user=> (collectiontype (list "bark" "moo" "meow")) :list user=> (collectiontype [:cat "meow", :dog "bark"]) :vector user=> (collectiontype {:cat "meow", :dog "bark"}) :map