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:
defn
defines a function;hello
is the function name; it takes one argument, name.- Java programmers will easily identify the
println
statement. - The
#'
indicates that the function just defined was stored in a Clojure variable. user
is the name of the current Namespace, andhello
is the function just defined.- The function is called with the argument as a string:
new guy
. - The expected output is printed.
nil
is the return value of theprintln
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.
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.
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
- Clojure — Functional Programming for the JVM
- Programming Clojure, Stuart Halloway (The Pragmatic Bookshelf)
- Clojure docs
- Notes on Leiningen