Getting Started with Clojure

0
5786
Getting started with Clojure

Getting started with Clojure

Clojure is a dynamic, general purpose programming language that targets the Java Virtual Machine (JVM) and the Common Language Runtime (CLR). It is designed for work and play.

If you play around with Java, you are ready to run Clojure. If not, you will have to install the Java Runtime Environment (1.5+ is recommended), and Ant, if you want to build the Clojure sources. Download the current snapshot of Clojure from github, extract the archive, and fire off ant. Once the build process is completed, you should have the file clojure.jar. Fire up the Clojure “prompt”, as follows:

$ java -cp clojure.jar clojure.main 
Clojure 1.3.0-master-SNAPSHOT 
user=>

The Clojure prompt is now ready for your instructions. Let’s try a few of them:

user=> (clojure-version) 
"1.3.0-master-SNAPSHOT" 

user=> (print)
nil 

user=> (print "Hello world") 
Hello worldnil 

user=> (+ 1 1) 
2

(clojure-version) is a built-in function that returns the current version of Clojure. This also demonstrates how you call a function in Clojure. The print function does the obvious. The nil that you see appended at the end of the Hello World string is the return value of the function, print. In Clojure, nil means nothing.

If you are familiar with any language of the Lisp family, you have definitely guessed correctly that Clojure is a Lisp dialect. Since I will not be talking about the basics of Lisp programming, you will benefit from this article if you are just a little familiar with a Lisp dialect. On the other hand, you could use this article as a starting point to learn Clojure programming, and get a feel of what Lisp is all about.

REPL

The user=> prompt is what is known as the REPL, or the read-eval-print-loop. The REPL is your key to world domination. A little Java library called JLine will help you in your quest by enhancing the editing support of the Clojure REPL. Once the JLine JAR is in your CLASSPATH, invoke Clojure REPL using:

java -cp jline-0_9_5.jar:clojure.jar jline.ConsoleRunner clojure.main

.
Let us now see how you can go about defining a simple function at the REPL:

user=> (defn hello [name] 
(println "Hello, " name)) 
#'user/hello 
user=> (hello "new guy") 
Hello, new guy 
nil 
user=>

Here is a line-by-line explanation of the above block of code:

  1. defn defines a function; hello is the function name; it takes one argument, name.
  2. Java programmers will easily identify the println statement.
  3. The #' indicates that the function just defined was stored in a Clojure variable.
  4. user is the name of the current Namespace, and hello is the function just defined.
  5. The function is called with the argument as a string: new guy.
  6. The expected output is printed.
  7. nil is the return value of the println function.

Working with Clojure source files

As you start experimenting more with Clojure, you will want to have your source code in a separate file, and then load it at the REPL. For example, here is a block of code that implements a simple number-guessing game:

;; Guess my number game 
;; Clojure port of the Common Lisp source by Conrad Barski 
;; in Land of Lisp, Chapter 2. 
;; Amit Saha 

;; globals 
(def small 1) 
(def big 100) 

(defn guess-my-number [] 
  (bit-shift-right (+ small big) 1)) 

(defn smaller [] 
  (def big (- (guess-my-number) 1)) 
  (guess-my-number) ) 

(defn bigger [] 
  (def small (+ (guess-my-number) 1)) 
  (guess-my-number) ) 

(defn start-over[] 
  (def small 1) 
  (def big 100) 
  (guess-my-number))

Now, load the file in the REPL using load-file. Let’s assume you have the number 15 in your mind, and you challenge the program to guess it. Here’s what a sample session would look like:

user=> (load-file "guessnumber.clj") 
#'user/start-over 
user=> (guess-my-number)
50 
user=> (smaller) 
25 
user=> (smaller) 
12 
user=> (bigger) 
18 
user=> (smaller) 
15

Editing and IDE support

Clojure is supported by most IDEs and various other editors out there. Since I personally use Emacs, I used Jeffrey Chu’s Clojure mode to edit the Clojure source files.

Interaction with Java

One of the main features of Clojure, as a Lisp dialect, is that it gives you access to the vast Java toolbox. Next, we will look at some basic usage of Java classes from Clojure. This example is taken from the book Programming Clojure, by Stuart Halloway:

user=> (new java.util.Random) 
#<Random java.util.Random@173ec72> 
user=> (def rnd (new java.util.Random)) 
#'user/rnd 
user=> (. rnd nextInt) 
1976620372 
user=> (. Math PI) 
3.141592653589793 
user=>

Using libraries

Our modest experience with Clojure so far has involved only the core features, or Clojure Core, to be technically accurate. You could consider these as the built-in features of Clojure. However, sooner rather than later, you will probably need to access the Clojure features that are packaged as third-party libraries.

Clojure-contrib is a collection of name-spaces, each of which implements various additional features. These libraries are also candidates for inclusion in the Clojure core. There are also a number of other libraries, which can be found at clojure.org/libraries — and, of course, Github will have a number of others. For a ready-to-use collection of Clojure libraries, see clojars.org.

In the next example, we will use a Clojure library, Incanter, which is a Clojure-based R-like statistical-computing environment for the JVM. Let us utilise an easy-to-use build tool for Clojure, called Leiningen. It is designed to “not set your hair on fire” — so the Github page claims. It lives up to those words quite well, if my initial experience is any indication.

First, let’s set up Leiningen, and then look at a simple use-case of Incanter. Download the lein script and chmod it to be executable. This shell script will be used to bootstrap Leiningen, and hence the first time you run it, it will download the Leiningen JAR in $HOME/.lein. Next, add the location of your lein script to your $PATH. Then, create a new project with: lein new incanter_demo. This step creates a new subdirectory (incanter_demo) for your project, with the following directory structure:

   . 
   |-- project.clj 
   |-- README 
   |-- src 
   |   `-- incanter_demo 
   |       `-- core.clj 
   `-- test 
       `-- incanter_demo 
               `-- test 
                       `-- core.clj

project.clj has the metadata about your project: version information, description, dependencies, etc. As mentioned, we will be using the Incanter Clojure library; hence, we need to add a dependency on Incanter. We also need to set an entry point for our application. Here is what project.clj looks like after these modifications:

(defproject incanter_demo "1.0.0-SNAPSHOT" 
  :description "Demo app using Incanter" 
  :dependencies [[org.clojure/clojure "1.2.0"] 
                 [org.clojure/clojure-contrib "1.2.0"] 
         [incanter "1.2.3"]] 
:main incanter_demo.core)

Next, we will edit the core.clj file to the following contents:

(ns incanter_demo.core 
  (:gen-class)) 
(use '(incanter core stats charts)) 
(defn -main [] 
  (println "Welcome to Incanter demo") 
  (view (histogram (sample-normal 1000))))

Finally, we will build our Clojure app using lein uberjar:

Cleaning up. -
Downloading: org/clojure/clojure/1.2.0-master-SNAPSHOT/clojure-1.2.0-master-SNAPSHOT.pom from clojure 
Downloading: org/clojure/clojure/1.2.0-master-SNAPSHOT/clojure-1.2.0-master-SNAPSHOT.pom from clojure-snapshots 
Downloading: org/clojure/clojure/1.2.0-master-SNAPSHOT/clojure-1.2.0-master-SNAPSHOT.pom from clojars 
Downloading: org/clojure/clojure/1.2.0-master-SNAPSHOT/clojure-1.2.0-master-SNAPSHOT.pom from central 
Downloading: org/clojure/clojure-contrib/1.2.0-SNAPSHOT/clojure-contrib-1.2.0-SNAPSHOT.pom from clojure 
Downloading: org/clojure/clojure-contrib/1.2.0-SNAPSHOT/clojure-contrib-1.2.0-SNAPSHOT.pom from clojure-snapshots 
Downloading: org/clojure/clojure-contrib/1.2.0-SNAPSHOT/clojure-contrib-1.2.0-SNAPSHOT.pom from clojars 
Downloading: org/clojure/clojure-contrib/1.2.0-SNAPSHOT/clojure-contrib-1.2.0-SNAPSHOT.pom from central 
Copying 38 files to /home/gene/clojure/incanter_demo/lib 
Copying 38 files to /home/gene/clojure/incanter_demo/lib 
Created /home/gene/clojure/incanter_demo/incanter_demo-1.0.0-SNAPSHOT.jar 
Including incanter_demo-1.0.0-SNAPSHOT.jar 
Including jline-0.9.94.jar 
Including incanter-charts-1.2.3.jar 
Including jlatexmath-0.9.1-20100323.073428-1.jar 
Including incanter-1.2.3.jar 
Including congomongo-0.1.2-20100502.112537-2.jar 
Including jtransforms-0.9.4.jar 
Including optimization-0.9.4.jar 
Including incanter-excel-1.2.3.jar 
Including avalon-framework-4.1.3.jar 
Including logkit-1.0.1.jar 
Including jcommon-1.0.16.jar 


. . Created /home/gene/clojure/incanter_demo/incanter_demo-1.0.0-SNAPSHOT-standalone.jar

Now that you have the standalone JAR for your project, run it like a typical Java JAR:

$java -jar incanter_demo-1.0.0-SNAPSHOT-standalone.jar.

You should see the following output:

Welcome to Incanter demo -

You should also see the plot, as shown in Figure 1. Now, if you go back to the project directory and list the contents of the lib subdirectory, you will see a bunch of JARs — which are basically the dependencies you specified in the project.clj file.

Incanter demo
Figure 1: Incanter demo

It is to be noted here that the option uberjar tells lein to build a standalone JAR for your application, so as to make it shareable. If, however, you just want to run your application, use lein run.

Having had a preliminary look at Clojure, the language, let us now learn a bit about using Clojure for Web applications.

Web frameworks for Clojure

While there is nothing to prevent you from using the Java Servlet API directly in your Clojure applications and deploying them as Web Archives (WARs), we will not do that today. Instead, we will take a brief look at one of the Clojure Web frameworks, Conjure. As the website claims, it’s a Rails-like framework for Clojure. How similar the two are can only be judged by a Rails aficionado, which I am not. So let’s use Leiningen to write a simple Web application using Conjure.

Create a new Clojure project; add conjure-core as one of the dependencies, and lein-conjure in the dev-dependencies list. The project.clj should look like what’s shown below:

(defproject hello-conj "1.0.0-SNAPSHOT" 
  :description "Hello Conjure!" 
  :dependencies [[org.clojure/clojure "1.2.0"] 
                 [org.clojure/clojure-contrib "1.2.0"] 
         [conjure-core "0.8.0"]] 
  :dev-dependencies [[lein-conjure "0.8.0"]])

Then execute lein deps to download all the dependencies, which will be stored in the lib/ directories. Now that the conjure plugin for Leiningen has been downloaded, let us convert this generic Clojure project into a Conjure project:

$ lein conjure new

This step will create a number of Conjure-specific subdirectories and files in the project folder, which you can view by using the tree command. Let us now test the working of our server: lein conjure server. You should see something like what is given below:

DEBUG [conjure.core.db.flavors.h2]: Executing query: ["SELECT * FROM sessions LIMIT 1"] 
DEBUG [conjure.core.db.flavors.h2]: Create table: :sessions with specs: (("id" "INT" "NOT NULL" "AUTO_INCREMENT" "PRIMARY KEY") ["created_at" "TIMESTAMP"] ("session_id" "VARCHAR(255)") ["data" "TEXT"]) 
INFO  [conjure.core.server.server]: Server Initialized. 
INFO  [conjure.core.server.server]: Initializing plugins... 
INFO  [conjure.core.server.server]: Plugins initialized. 
INFO  [conjure.core.server.server]: Initializing app controller... 
INFO  [conjure.core.server.server]: App controller initialized. 
2011-02-13 16:09:37.909::INFO:  Logging to STDERR via org.mortbay.log.StdErrLog 
2011-02-13 16:09:37.911::INFO:  jetty-6.1.14 
2011-02-13 16:09:37.946::INFO:  Started SocketConnector@0.0.0.0:8080
. 
.

Now, you can visit the URL http://127.0.0.1:8080 and you should see a default Conjure home page, as shown in Figure 2.

Conjure Home
Figure 2: Conjure Home

Congratulations! You can change the default file, which is in src/view/home/index.clj, and see the changes automatically; no server restart is required.

Where next?

In this admittedly whirlwind tour of Clojure, we have taken a look at some of the basic features of this relatively new language, and have become somewhat familiar with its ecosystem. The next steps will have to be taken based on what your area of interest is.

Accessing SQL and NoSQL databases and multi-threaded applications (which, incidentally, happen to be one of Clojure’s selling points) are a couple of areas which can be immediately looked into, especially for building scalable Web applications. Before we part, here’s something the Android fans among you should love. There is a Clojure REPL application available in the Android market place, which you can install for free and program in Clojure on the go!

Resources
  1. Clojure — Functional Programming for the JVM
  2. Programming Clojure, Stuart Halloway (The Pragmatic Bookshelf)
  3. Clojure docs
  4. Notes on Leiningen

LEAVE A REPLY

Please enter your comment!
Please enter your name here