# Seven Languages In Seven Weeks: Clojure - Day 1

Posted January 19, 2011 at 10:04 AM by Ben Nadel

Tags: Lisp, Clojure

After a few weeks off from my Seven Languages in Seven Weeks book by Bruce Tate, I just started the sixth language: Clojure. Clojure is a version of LISP that runs on the JVM (Java Virtual Machine). LISP comes from the phrase, "List Processing;" the reason for this will become evident the moment you look at the code which consists of list of lists of lists. Back in college, my Artificial Intelligence (AI) teacher joking defined LISP as "Lots of Irritating Superfluous Parenthesis."

To be completely honest, LISP was not something that I could wrap my head around in college. In my AI class, we needed to write a LISP program that moved a robot through a maze (digitally); I was unable to complete the assignment. I brought much shame upon my family.

This time, it's personal!

HW1: Implement a function called (big st n) that returns true if a string st is longer than n characters.

Before we get into the code, I should probably mention that, unlike any of the other languages that we've looked at so far, Lisp uses Prefix Notation. This is a type of structuring in which the first element in a list is the function and the the rest of the elements in the list are all parameters to that function. So, in our assignment, "big" is the function and "st" and "n" are the two parameters. This style holds true for all operators as well, including "=" and ">", which you'll see in the following code.

• ;-- Implement a function called (big st n) that returns true if a
• ;-- string is longer than n characters.
•
•
• ;-- Define our function.
• (defn
• big
• [input targetLength]
• (> (count input) targetLength)
• )
•
•
• ;-- Now, let's test our function.
• (println (big "" 3))
• (println (big "h" 3))
• (println (big "he" 3))
• (println (big "hell" 3))
• (println (big "hello" 3))

Here, we are using the function, defn, in order to define the "big" function. This function (defn) takes three parameters: the name of the function we are defining, the vector of arguments, and the body to execute. As you can see (or try to see), our function returns whether or not the length of the incoming string is bigger than the target length.

We are then testing the big function over a set of increasingly long string values. When we run the above code, we get the following console output:

false
false
false
true
true

As you can see, once we reached a string length of 4 - "hell" - our big function started returning true.

HW2: Write a function called (collection-type col) that returns :list, :map, or :vector based on the type of collection col.

Clojure has a bunch of core functions for testing data types. As such, for this solution, I'm just throwing those in a (cond) statement - Lisp's version of a Switch/Case statement - and returning the appropriate symbols:

• ;-- Write a function called (collection-type col) that returns
• ;-- :list, :map, or :vector based on the type of collection.
•
•
• ;-- Define our function.
• (defn
• collection-type
• [input]
• (cond
• (list? input) :list
• (map? input) :map
• (vector? input) :vector
• )
• )
•
•
• ;-- Define our various data types to test again.
• (def myList '(1 2 3))
• (def myMap {:a 1, :b 2, :c 3})
• (def myVector [1 2 3])
•
•
• ;-- Output the class types for the three test values in order to
• ;-- make sure that we know we are dealing with the correct test
• ;-- data types.
• (println "myList:" (class myList))
• (println "myMap:" (class myMap))
• (println "myVector:" (class myVector))
•
• (println "")
•
• (println "myList:" (collection-type myList))
• (println "myMap:" (collection-type myMap))
• (println "myVector:" (collection-type myVector))
•
• ;; And one test for nil on an unexpected collection type.
• (println "Nil Test:" (collection-type #{}))

Once I have my (collection-type) function defined, I then create a number of data structs against which to test the function. When we run the above code, we get the following console output:

myList: clojure.lang.PersistentList
myMap: clojure.lang.PersistentArrayMap
myVector: clojure.lang.PersistentVector

myList: :list
myMap: :map
myVector: :vector
Nil Test: nil

As you can see, all my tests return the appropriate value except for the Set - my Nil test. Because my (cond) statement does not have a condition for Set values, it returns nil which becomes the result of the (collection-type) function call.

When I first approached this problem, I tried to come up with my own way to test for type. Before I found the (list?) and (map?) style functions, I found the (instance?) function. As such, I thought I could check to see if the incoming collection was an instance of the various types of data I was looking for.

This approach proved to be immediately problematic as the same type of data appears to be modeled by difference classes. To see what I mean, take a look at this code:

user=> (class '(1 2 3))
clojure.lang.PersistentList
user=> (class '())
clojure.lang.PersistentList\$EmptyList

Both of these lines check the class for the given list. However, notice that the empty list is actually modeled by a different class (what appears to be an inner class). Furthermore, these classes are not equal:

user=> (= (class '()) (class '(1 2 3)))
false

... and, the empty list is not an instance of the populated list:

user=> (instance? (class '(1 2 3)) '())
false

As you can see, there doesn't appear to be any form of implicit up-casting of data types when using the (instance?) function. In the end, however, it didn't matter because the (cond) approach is definitely way cleaner and more concise than my first idea.

As someone who is a stickler for code formatting and readability, I suspect that finding the right mix of line breaks in Lisp will be challenging. However, after this homework, I am remaining hopeful that this time around, I'll be able to figure out what this Lisp thing is all about.

### You Might Also Be Interested In:

Jan 19, 2011 at 10:27 PM // reply »

Clojure is mylanguage for this year. I attended the 2010 ClojureConj here in RTP and it was great. There will probably be another one in October 2011 so come on down to North Carolina.

I went to hear Stu Halloway last night at the Ruby meeting in RTP. He did a talk "Clojure for Rudy Devs" that was good in content and due to the fact that he is a great speaker.

I also have been trying to learn Clojure on my own so it has been a bit of a struggle. I look forward to more of your posts.

Jan 20, 2011 at 10:49 AM // reply »

@Roger,

Tate actually mentions Halloway in the book as the author or Programming Clojure [Hal09]... I think; I am can't find the reference at the moment. It would be cool to hear him talk.

How did you get started with Clojure anyway? Having found Lisp so challenging in college, I am sure I would have never gone down this road if the book didn't require it; although, the door swings both ways - now that I am trying it, I am feeling really good about myself as I make progress. Like I said in the post, this time it's personal ;)

I actually just posted Day 2 if you are interested:

It took me a frustrating 4 hours, but it's starting to make more sense.

Jan 20, 2011 at 7:01 PM // reply »

Halloway is CEO of Relevance over in Durham so he is local to me. You can see a number of his talks on the InfoQ site <http://www.infoq.com/Clojure> Stu and Rich Hickey videos are pretty good.

I had heard Sean Corfield talk some about Clojure on-line and then I got wind of the first ClojureConj conference that was to be held near where I work in RTP. I contacted Sean for some guidance on whether it would be a good event for me. He was very supportive and wished that he did not have a conflict with it. It was inexpensive and I didn't have to travel so I went and was glad I did. It was a very supportive group of people similar to the CF crowd.

I had tried to get started with just the book, but the conference really did help. The on-line videos helped a lot too just to get familiar with the concepts. I wish they would do a noob class along with the next conference. It will probably come back here again sometime in October 2011.

I'm still learning and definitely at the noob stage. I don't have a lot of time to learn things and I spent a good bit of time learning .NET stuff last fall so Clojure fell to the side until just the last few weeks. Good luck with it, Roger (hope you make it to NCDevCon 2011)

Jan 24, 2011 at 5:26 PM // reply »

Great to see you being more successful with Clojure than you were with Lisp all those years ago! Despite the four hours for each day of exercises, I hope you ultimately enjoyed the experience and learned a lot - things you can apply to solving problems in other languages?

I'm going to make one idiomatic observation and that's on parentheses placement: the standard idiomatic Lisp layout for parentheses is to close them all on one line rather than on separate lines indented as you have them.

See http://blog.fogus.me/2010/08/30/community-standards/ for an amusing commentary on the discussion of Clojure / Lisp parentheses placement and the related Clojure Golf post for more traditional code layout.

Roger, I'll see you at Clojure Conj 2011 I hope. Ben, maybe see you there too? :)

Jan 24, 2011 at 8:29 PM // reply »

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

 Author Name: Author Email: Author Website: Comment: Supported HTML tags for formatting: bold   italic   code Remember my information Subscribe to comments Send me a copy of this comment
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
May 14, 2013 at 6:57 PM
The UX Of Prototyping: Low-Fidelity Is The New High-Fidelity
@Phillip, I'm not sure I follow what you mean? Are you saying that you looked at the list of widgets provided by the jQuery UI and let that be your style guide? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools