Wednesday 29 June 2011

Clojure entertainment at 4clojure

The site 4clojure.com has a graduated series of tests on Clojure.  Each test presents you with one or more Clojure statements with gaps in them. The objective of each exercise is to provide some Clojure code to fill in the gap to create a meaningful Clojure expression that evaluates to true.  When you click the Run button the web page evaluates your code and tells you whether you have got it right.

The nice effect of this site is that it takes you away from the grand scheme and makes you think about the icky details.

The first puzzle gets you to note that true is a valid Clojure word that evaluates to boolean true.

Next we have a simple piece of arithmetic illustrating the operator-first lisp type notation.

Next we have an example of a method call.  In the expression

(.toUpperCase "hello world")

the first argument .toUpperCase must of course evaluate to a function - but the dot at the beginning indicates that this is a call to a method on a Java class - but which class?  Clojure works this out from the type of the
next argument, the string "hello world".

The next tests introduce lists and vectors.

Lists you can create with a literal or a function call, as '(:a :b :c) or  (list :a :b :c).

For vectors there is the literal form and two functions, so you can say [:a :b :c] or (vector :a :b :c) or (vec '(:a :b :c)).

What surprised me at this point is that the vector and the list are equal, that is:-

(= (list :a :b :c) (vector :a :b :c)) --> true

The function conj adds one or more new elements to a collection and returns a new collection.  However, conj adds the elements "at an efficient insertion spot for the underlying data structure" (Halloway p.95)

This means that when you conj into a list the added elements go in at the beginning:-

(conj '(3 4) 2 1) => (1 2 3 4)

But for a vector the new elements go in at the end:-

(conj [1 2] 3 4) => [1 2 3 4]

When you conj an element into a set then the set decides whether to accept the new element and where to put it.

Clojure uses functions first, second and rest where in trad Lisp you would have car, cadr and cdr.

Anyway, a very nice site and it runs very smoothly and gives you the appropriate exception report when you do something invalid.

Hello World in Clojure

For the first script in Clojure naturally we want to see Hello World.  In this case the script checks to see whether there are any command line arguments: this is passed in to the script via the global identifier *command-line-args*. If not, it writes Hello World to the standard output: if there are arguments it takes the first item and uses that in its greeting.

I don't think there is an explicit entry point in a Clojure program: the interpreter just starts running the first runnable code it finds.

The namespace directive at the top reflects the path to the script: in a file helloworld.clj which is in a folder examples which is in a folder that is in the classpath passed to Clojure by the script that calls the interpreter.

So we run the script from the folder c:\Users\phancock\Documents\Clojure as follows:-


>clojure examples/helloworld.clj
Hello World
>clojure examples/helloworld.clj Polly
Hello Polly


ok.  So this is the script:-


(ns examples.helloworld)
(if (empty? *command-line-args*)
    (println "Hello World")
    (println "Hello" (first *command-line-args*)))


The hard part is just getting the choreography of paths and class paths and namespaces clear in my mind. This is the bit that the books skim over to get to the easy stuff, writing the code. "With these mechanical details mastered, everything else is comparatively easy" (Kernighan & Ritchie p.6)

Wednesday 22 June 2011

Programming Clojure

So, I'm going to take a look at programming Clojure, with some help from the book "Programming Clojure" by Stuart Halloway, published by the Pragmatic Programmers.

To get Clojure running, I've downloaded clojure-1.2.0.zip, which is the core stuff, and clojure-contrib-1.2.0.zip, which is a library of extra modules.  There's no installation process necessary - I've just unzipped these into folders in c:\Program Files (I'm on Windows 7).

Now I've created a folder c:\Users\Phancock\Documents\Clojure, where I will be putting my own code.

So finally I need a batch file that will invoke the Clojure interpreter.  This sets up the classpath to the Clojure libraries and calls Java with the namespace clojure.main, and passes the name of the script you want to run and any parameters.  So my script looks like this:-


@echo off
set CLOJURE=c:/Program Files/clojure-1.2.0/clojure.jar
set CONTRIB=c:/Program Files/clojure-contrib-1.2.0/target/clojure-contrib-1.2.0.jar
set DEV=c:/Users/phancock/Documents/Clojure
java -cp "%CLOJURE%;%CONTRIB%;%DEV%" clojure.main %*