Saturday, May 21, 2011

Clojure Lists and Forms

I'm working through Programming Clojure by Stuart Halloway.  I am at the middle of chapter 2 (exploring Clojure).  The syntax is different to anything I have used before and it's little hard to understand at times so I have decided to take time to do some background research.  


As usual, Google throws up a page from the fountain of all knowledge - Wikipedia's article on Lisp.


Lists

Clojure is a Lisp implementation (aka "a Lisp").  The name Lisp derives from "LISt Processing" because in a Lisp, everything is represented as a list like this one.
(foo 1 2 3)


The list is enclosed in parenthesis and the items in the list (known as atoms) are separated by spaces.  The first atom is an operator (usually a function call; foo in this case) and the remaining atoms (1,2 and 3) are arguments to the function.  The bracket notation is known as an S-expression and the use of the first atom in the list to represent an operator is called prefix notation.  Prefix notation provides a very regular syntax that make it easy to generate code for metaprogramming.  


So, if we know the str function creates a string from it's arguments, we can write 
(str "hello " " world") 
=> hello world


This looks quite similar to most programming languages, but it looks a bit odd when you see a arithmetic operation for the first time
(+ 1 2 3) 
=> 6


Most languages use infix operators for arithmetic so in Java or Ruby this s-expression would be 
1 + 2 + 3 


Clojure runs on the JVM and it also provides direct access java.lang.  You can call java functions by prefixing the operator atom with a dot.
"foo".toUpperCase();
becomes 
(.toUpperCase "foo")
=> FOO

As you would expect, s-expressions can be nested to any depth:
(str (str "hello" " world") (str " from" " me"))
=> "hello world from me"
(+ (- 3 (* 2 5)) 8)
=> 1

Forms

Lisp code is read by a reader that can be programmed (in most Lisps - see below) using macros.  These macros are pretty sophisticated and go beyond the pre-processor templating features in languages like C.  For example, Clojure implements a macro that tells the reader to ignore everything after a semi-colon  - in other words, a line comment.

(+ 1 2 3)  ; Comment: Adds 3 numbers together

I would need to dig deeper to find out, but I can image there *may* have been a time when everything in lisp was represented as an s-expression with a bunch of reader macros to provide shortcuts and "syntax".  I'm sure that would have been possible, but it would have severely limited portability because I would need to have your macros to run your code, and they might conflict with mine.

Thankfully, Clojure provides proper syntax for important constructs and a limited set of reader macros that cannot be extended.  The syntax elements are known as forms


Form
Usage
Syntax
Example
Boolean
Conditional logic
true, false
true, false
Character
A single character
\<char>
\a
Keyword
An constant value that refers to itself - like a Symbol in Ruby
:<name>
:foo
List
S-Expressions, lists of data
(*<atoms>)
(str "a" "b")
Map
Hashes
{key1 value1, key2 value 2}
{:name "Bill", :age 42} 
Nil
Nil
nil
nil
Number
Integers, decimals
*digits[.*digits]
100, 12.45
Set
A set of non-duplicate values
#{<value1> <value2>}
#{1 "a" :foo}
String
A (java) string
"<text>" 
"foo"
Symbol
A handle on an entity - e.g. a function
*<text>
user/foo, java.lang.String 
Vector
An ordered sequence of data separated by spaces
[<value1> <value2>]
[1 :bar "x" 4.3 \a true]


I don't know whether these are native to Clojure or borrowed from other Lisps, but it's not really important to my learning right now.

The usage for these forms is pretty much as you would expect.  We've already seen the string and number literals in use above.  I won't document them there because there are plenty of Internet resources out there.  

* Chapter 2 of Programming Clojure covers all the forms in detail

Note though that clojure is a dynamic language so you can mix an match different types within a data structure.

The conj function pushes items into a vector
(conj [1 2] 3)
=> [1 2 3]

We can also mix up the types
(conj [] 1 2.3 \s "foo" nil true)
=> [1 2.3 \s "foo" nil true]

Learnings

The important thing to remember is that everything is an s-expression.  Sometimes it can be hard to see in more complex expressions but you can usually figure out what is going on if you break everything down into a list and look for the s-expression.

Division in Clojure

Clojure includes a Ratio type which we can access using a ratio literal like this
(+ 2/3 3/4)
=> 17/12


You need to be careful because the '/' operator will return a ratio if the result is not a whole number (most languages return an integer)
Ruby: 16/7
=> 2
Clojure: (/ 16 7)
=> 16/7


The % sign means something different (the first argument to an anonymous function actually) rather than being a modulus operator
(% 16 7)
java.lang.IllegalStateException: arg literal not in #()


If you want to do integer division or get the mod, you need to use the quot (quotient) and rem (remainder) functions
(quot 16 7)
=> 2

(rem 16 6)
=> 4


You can also use decimal numbers to do decimal division
(/ 16.0 7)
=> 2.2857142857142856

Monday, May 16, 2011

Early Explorations in Clojure

Having never programmed in Lisp before, and never really been able to start making sense of the code snippets I've seen, this is all very new to me.  However, I've got the following figured out:

Function calls are surrounded with parenthesis and arguments are separated by spaces not commas.  String literals are surrounded by quotes.  

Print "hello world" to stdout:
(println "hello world")

Single quotes cannot be used for string literals though
(println 'hello world')
java.lang.Exception: Unmatched delimiter: )

Clojure provides access to the core java libraries - albeit with some slight syntax changes...

Java:
System.out.println(System.getProperty("user.dir"));


Clojure:
(println (System/getProperty "user.dir"))

You can use defn to declare a function.  Notice the argument list in square brakets. 
(defn foo [bar baz] (str bar "," baz))
(foo 1 2)
==> "1,2"

The str function concatenates the strings passed.


Sunday, May 15, 2011

Clojure

I'm probably biting off more than I can chew, but I've started looking at Clojure as well as JavaScript. I've been thinking of learning a functional language for some time now and JavaScript's focus on functions over classes and objects in the classical sense has inspired me to give it a go.

JavaScript Books

I'm finding twitter increasingly useful now that my network has grown to include people I know from Scottish Developers events and Code Retreats and I'm having conversations rather than just lurking on discussions.


My JavaScript doesn't extend much beyond the obvious syntax (variables, loops etc) and a rudimentry understanding of the DOM.  I clearly need to brush up a bit before digging into node.js and jasmine.  I don't want to even thing about coffee script before I understand the project it solves. 


So where should I start?  I asked the twitterverse:




Within minutes I had a response! 


Matthew Gillard and Bill Caputo both recommended JavaScript: The Good Parts by Douglas Crockford.  They also recommend:




Certainly a lot to be getting on with


Tools-wise, I downloaded chrome and Firefox and installed the Firebug plugin. 


That was a week ago.  So far, I prefer Chrome.  I like it's mimimal style.  I also like the way firebug highlights the relevant area on the page when you click the markup.


The book is truly awesome.  I would definitely recommend it.









Scottish Ruby Conference 2011

So here we go.  I've been meaning to start a blog about all the things I do outside Agile data management for a while.  Hopefully this will work out.  Let's see...


The Scottish Ruby Conference this year was just what I needed.  As ever, it was really inspirational and motivated me to kick-start my learning.  Someone said that if you heard something mentioned 3 times at a conference, those are the things you should be learning.


My 3+ list is 
Strange that the first three are Javascript technologies, but I guess that's just the way it worked out this time.

I guess I had best brush up on my javascript then.