- Professional Skills
- Articles
- Bookmarklets
- Javascript Console For IE
- Neural Net Extension for Ruby
- Writing a PDF Generation Framework In Ruby
- Developing Mambo Components
- PayPal Website Payments Pro
- Bulk File Renaming
- Displaying a Maintenance Page
- Ruby: escape, unescape
- Clojure Tutorial For the Non-Lisp Programmer
- Complex mocking with PHPUnit
- PHP Coding Tips
- Simple CRUD Application
- External Links
- Recent posts
Clojure Tutorial For the Non-Lisp Programmer
Submitted by moxley on Thu, 2008-05-01 06:30
To create a global variable, use the
Using
The
The
The
The
The
The
Clojure is a new programming language that uses the Java Virtual Runtime as its platform. Clojure is a dialect of Lisp. The language home page is at http://clojure.org/.
Table of Contents
A Quick Comparison
Installing Clojure
Atoms
Lists
Vectors, Maps and Sets
Defining Variables and Functions
Special Forms
Java Integration
Looping and Iterating
Sequences
A Quick Comparison
In C-like languages, a function call might look something like this:
do_something_with(value1, value2)
In Clojure, the same function call would look like this:
(do-something-with value1 value2)
Here, Clojure differs in this way:
- The opening parenthesis is to the left of the function name.
- There are no commas delimiting the function parameters.
- By convention, words in a function name are separated by dashes.
There’s not a huge difference here.
Here’s how adding two values might look in a C-like language:
value1 + value2
Here’s how it would look in Clojure:
(+ value1 value2)
This time, the difference is bigger because the plus sign comes before the parameters. In C-like languages, the plus sign is a type of Operator. In Clojure, it’s just a function with the name ‘+’. Clojure doesn’t separate the concept of “operator” from “function” like C-like languages. Everything that is an operator in a C-like language has to be implemented as a function in Clojure. If your favorite C-like language didn’t have its operators, adding two values might look something like this:
add(value1, value2)
However, now that your C-like language doesn’t have any operators, those characters that were used for operators are now freed to be used elsewhere, such as in function names:
+(value1, value2)
Now it doesn’t look much different than the same statement in Clojure:
(+ value1 value2)Installing Clojure
There are two ways to install Clojure: by release package, or by Subversion.
It is assumed you already have the Java Virtual Machine (JVM) installed, and you know how to access your system’s CLI (Command Line Interface).
Installing by release package:
- Go to the Clojure home page, follow the link for Download, and download the Clojure package. It’ll probably be a ZIP file.
- Unzip the ZIP file, if your browser hasn’t done so automatically.
- From your CLI, navigate (using the ‘cd’ command) to the unpacked Clojure folder.
- Enter the command:
java -cp clojure.jar clojure.lang.Repl(The ‘-cp’ (classpath) argument may vary depending on which brand of JVM you have.) - You should now be at the command prompt:
user=>
Installing from a Subversion checkout:
If you have Subversion and Ant installed on your system, it is recommended that you checkout the Clojure from the repository instead of downloading a release package. Clojure is a new language, and changes come quickly. You will need Java 5, Ant, and Subversion (the ‘svn’ command) already installed. Here’s how to do it from the command line:
- Enter the following commands:
svn co https://clojure.svn.sourceforge.net/svnroot/clojure/trunk clojurecd clojureantjava -cp clojure.jar clojure.lang.Repl(The ‘-cp’ (classpath) argument may vary depending on which brand of JVM you have.)- You should now be at the command prompt:
user=>
The command prompt is known as the REPL (Read-Evaluate-Print-Loop). The REPL Reads expressions that you give it, Evaluates the expressions, Prints the value that is the result, and Loops around for more input.
Atoms
There are two categories of Clojure expressions, atoms and lists. Atoms are like the primitive types in other languages. Let’s use the REPL to explore some atoms.
Numbers
user=> 5
5
The number 5 is evaluated and the result is displayed.
Booleans
Here’s another atom:
user=> true
true
Clojure supports boolean TRUE and FALSE values, represented as true and false respectively.
Nil
Here is another important atom:
user=> nil
nil
This is Clojure’s name for no-value, or null. It is the same as Java’s null.
Strings
Here is a Clojure string:
user=> "Hello, world!"
"Hello, world!"
Clojure strings follow the same rules as Java strings, so for instance, "\t" represents the ASCII TAB character. The Java API is the primary way to make calculations on a string.
Symbols
Symbols are names that are normally used to bind to a value. They do not have to bind to a value though. A symbol has an underlying object (not the bound value), and to access that object, prepend the symbol’s name with a single-quote:
user=> 'x
x
To access the value that the symbol binds to, use the symbol’s name directly:
user=> x
1
If the symbol is not bound to anything, you can use the symbol by itself, but it is an error to try to access the symbol’s bound value:
user=> foo
java.lang.Exception: Unable to resolve symbol: foo in this context
...
Keywords
Keywords are like symbols, except that they do not directly bind to anything. Keywords always start with a colon (:). Here are some keywords:
user=> :a
:a
user=> :_123
:_123
user=> :KEY
:KEYLists
Atoms can be grouped together within lists. Lists can have zero or more atoms, enclosed in parentheses. The list’s elements are delimited with a space. Lists can be used to perform an operation, like this:
user=> (+ 3 3 3)
9
This operation takes three numbers and adds them together. When Clojure evaluates a list, the first element of the list—called the operator—determines the type of operation to be performed. The remaining elements are called the arguments.
A list that performs an operation with a named operator is called a form. There are three kinds of forms: functions, macros, and special forms.
List items can be atoms, lists, or other data structures that are part of Clojure.
user=> (list :foo (list 1 2 3) [4 5 6])
(:foo (1 2 3) [4 5 6])
Although the list syntax is used for performing operations, it can also be used to represent data. There is an important consequence of code and data sharing the same syntax: code can be manipulated as if it were data because it is data.
To create a list to be used as data, use Clojure’s built-in operation, list:
user=> (list 1 2 3)
(1 2 3)
user=> (list a b c)
(a b c)
user=> (list "one" "two" "three")
("one" "two" "three")
Clojure also has a short-cut syntax for creating a list as data. Just prepend the list with a single-quote character:
user=> '(1 2 3)
(1 2 3)
Creating a list this way has a slightly different effect. The list items are left unevaluated.
Using some of Clojure’s built-in operations, information can be extracted from the data. The following expression returns the first element of the given list.
user=> (first '("one" "two" "three"))
"one"
Another operation returns all the elements except the first:
user=> (rest '("one" "two" "three"))
("two" "three")
Vectors, Maps, and Sets
In addition to lists as a data type, Clojure provides syntax for defining vectors, maps and sets. Vectors are zero-based arrays. Here are a few examples:
user=> [1 2 3]
[1 2 3]
user=> []
[]
user=> ["a" "b" "c"]
["a" "b" "c"]
user=> [:foo "bar" 3]
[:foo "bar" 3]
user=> [1 2 [10 20]]
[1 2 [10 20]]
Here, vectors are very similar to lists. The difference is in the underlying data structure. Lists and vectors have different performance characteristics.
Another difference is that the vector syntax does not result in an operation being performed. Only the list syntax can be used to perform an operation.
You can also create a vector by passing a number of elements to the
vector operator:
user=> (vector 1 2 3)
[1 2 3]
Maps define a set of unique key-value pairs:
user=> {"a" 1, "b" 2, "c" 3}
{"a" 1, "b" 2, "c" 3}
The map above maps the string "a" to the number 1, "b" to the number 2, and "c" to the number 3. The commas between each pair are optional, to enhance readability of the code. Clojure treats the commas nearly the same as whitespace. You can put commas anywhere between elements of an expression:
user=> {"a" 1 "b" 2 "c" 3}
{"a" 1, "b" 2, "c" 3}
user=> {"a", 1, "b", 2, "c", 3}
{"a" 1, "b" 2, "c" 3}
user=> {"a" 1 ,"b" 2 ,"c" 3}
{"a" 1, "b" 2, "c" 3}
Notice that Clojure tries to keep track of the fact that commas were used. This is for convenience only.
Once a map is defined, its values can be looked up from key values using the get form:
user=> (get {"a" 1, "b" 2, "c" 3} "a")
1
user=> (get {"a" 1, "b" 2, "c" 3} "b")
2
user=> (get {"a" 1, "b" 2, "c" 3} "c")
3
user=> (get {"a" 1, "b" 2, "c" 3} "d")
nil
However, there’s a shortcut for this:
user=> ({"a" 1, "b" 2, "c" 3} "a")
1
user=> ({"a" 1, "b" 2, "c" 3} "b")
2
user=> ({"a" 1, "b" 2, "c" 3} "c")
3
user=> ({"a" 1, "b" 2, "c" 3} "d")
nil
Maps can be used as functions of their keys. This may seem a little weird at first, but eventually it makes a lot of sense.
There is yet a third way to get a value from a key:
user=> (:a {:a 1, :b 2, :c 3})
1
user=> (:b {:a 1, :b 2, :c 3})
2
user=> (:c {:a 1, :b 2, :c 3})
3
user=> (:d {:a 1, :b 2, :c 3})
nil
It’s important to get familiar with the last two usages, as they are commonly used in Clojure programs.
Defining Variables and Functions
def
To create a global variable, use the def form:
user=> (def x 5)
#'user/x
user=> x
5
user=> (+ 5 x)
10
user=> (def my-list '(1 2 3))
#'user/my-list
user=> my-list
(1 2 3)
user=> (last my-list)
3
There a a few things going on when a variable is created. What gets returned from def is a var, which is a an object that holds a value, such as 5. Also, a symbol is created, and that symbol is bound to the var.
defn
Functions can be created using defn:
user=> (defn election-year? [year]
(zero? (rem year 4)))
#'user/election-year?
user=> (election-year? 2007)
false
user=> (election-year? 2008)
true
user=>
Functions are just a kind of object that can be called.
The first argument to a defn is the function’s name, which becomes a symbol bound to the function. The second argument is the function’s argument list. Argument lists are always represented by a vector. The remaining arguments of defn can be one or more expressions. The result of the last expression is used as the function’s return value.
Using fn
Anonymous functions can be created using fn:
user=> (fn [x] (+ x 1))
user.eval__2384$fn__2386@c4b579
user=> ((fn [x] (+ x 1)) 9)
10
Since functions are just objects, they can be bound to a symbol (assigned to a variable):
user=> (def plus-one
(fn [x] (+ x 1)))
#'user/plus-one
user=> (plus-one 9)
10
The defn form is just a macro that turns its contents into a def + fn combination.
The doc form
Nearly all the forms in Clojure have built-in documentation. To quickly find out about a form, pass the form’s name to the doc form:
user=> (doc first)
-------------------------
clojure/first
([coll])
Returns the first item in the collection. Calls seq on its
argument. If coll is nil, returns nil.
nil
Documenting a function
There are multiple ways to add documentation to a function. Here is the easiest:
user=> (defn plus-one
"Returns a number one greater than x"
[x]
(+ x 1))
#'user/plus-one
user=> (doc plus-one)
-------------------------
user/plus-one
([x])
Returns a number one greater than x
nil
Here is another way:
user=> (defn plus-one
{:doc "Returns a number one greater than x"}
[x]
(+ x 1))
#'user/plus-one
user=> (doc plus-one)
-------------------------
user/plus-one
([x])
Returns a number one greater than x
nilSpecial Forms
Clojure has several built-in forms, known collectively as special forms. This section introduces of these forms and delves further into the types of expressions that are possible with Clojure.
The str form:
The str form concatenates two or more values, converting them to strings if necessary, and returns the result:
user=> (str "Hello," " world!")
"Hello, world!"
user=> (str 5)
"5"
user=> (str "Value: " 5)
"Value: 5"
The if form
The if form is similar to the if statement in C-like languages.
user=> (if true "yes")
"yes"
user=> (if false "yes")
nil
user=> (if false "yes" "no")
"no"
user=> (if nil "yes" "no")
"no"
user=> (if "" true)
true
user=> (if 0 true)
true
user=> (if true "yes" "no")
"yes"
user=> (if (= 1 1) "yes" "no")
"yes"
user=> (if (= 1 1) (+ 2 3) (+ 5 5))
5
user=> (if (= 1 2) (+ 2 3) (+ 5 5))
10
If the first argument, converted to a boolean, is true, then the second argument is returned. Otherwise the third argument is returned. The third argument is optional.
In Clojure, when a value is converted to boolean, it is always TRUE, unless the value is false or nil. There are many forms that make decisions based on whether a value will be true or false when converted to boolean.
The if form works a lot like the C-language ternary operator:
v = true ? 1 : 0
The ternary operator is usually used in places where an if statement is too verbose. However, since Clojure’s if form is already succinct, there is no need for a separate operator. You can still break up the expression onto separate lines when it makes sense to do so:
user=> (if (= 1 1)
(+ 2 3)
(+ 3 4))
5
user=> (if (= "foobar" (str "foo" "bar"))
"'foo' plus 'bar' equals 'foobar'"
"'foo' plus 'bar' does not equal 'foobar'")
"'foo' plus 'bar' equals 'foobar'"
The do form:
The do form is used to execute a number of operations in sequence. Typically in functional programming, expressions are contained by, or are containers for, other expressions, so there isn’t a need to execute operations one after the other. This is fine when the expressions produce a value that will be used by a containing expression. However, there are some occasions where the value of an expression isn’t used. If such an expression does anything useful at all, it is said to have side effects. For example, writing something to standard output, or a file, or a database, are all examples of side-effects.
Clojure provides the println form for writing to standard output. In order to use println within an expression whose return value we care about, we need to put it in a do expression:
user=> (do (println "Hello.") (+ 2 2))
Hello.
4
user=> (do (println "Hello.") (println "Hello again.") (+ 2 2))
Hello.
Hello again.
4
The do operation executes each expression in sequence and returns the result of the last expression.
The do form isn’t the only form that lets you perform a number of operations in sequence. let, defn and fn all let you do that too.
One of the things that takes some getting used to is that Clojure is a functional language. All expressions in Clojure return a value. Often, a single Clojure expression will span several lines, where the C-like programmer would write it out the same logic as a block of code consisting of several distinct statements. The distinct statements may assign a value to a variable to be used in the following statements. Programs written in functional languages tend to have larger statements spanning multiple lines rather than a multiline block of code split into smaller statements. This way of building programs can take some getting used to, but once you’ve learned it, the new way can be just as easy as the old. There are several advantages to writing programs this way.
The when form
The when form is similar to the if form. The differences are that there is no “else” condition, and more than one expression can be added to the when form for evaluation when the condition is TRUE.
user=> (when nil "Should return 'nil'")
nil
user=> (when false "Should return 'nil'")
nil
user=> (when true "Yes")
"Yes"
user=> (when true 1)
1
user=> (when true 1 2 3)
3
user=> (when true
(println "Hello, world")
"Yes")
Hello, world
"Yes"
user=> (when (= 5 (inc 4))
"Yes")
"Yes"
The let form
The let operator is used for setting up and holding temporary values to be used by a containing operation.
user=> (let [x 2] (+ x 8))
10
user=> (let [x 2 y 8] (+ x y))
10
user=> (let [x 2 y 8] (= (+ x y) 10))
true
user=> (let [x 3] (+ (* x x) 1))
10
user=> (let [color "Red"] (str "Color is: " color))
"Color is: Red"
user=> (let [color "Red" phrase (str "Color is: " color)]
(str "Clojure says: " phrase))
"Clojure says: Color is: Red"
The let form creates a temporary var (x and y in this case), that can only be used inside the body of the let expression. A vector is used to define the var and its value, and vectors are also used by other Clojure forms to declare a list of temporary variables and their assigned values. The vector contains name-value pairs.
Java Integration
Clojure provides the ability to interface with Java objects and primitives. Knowing how to do this is essential for non-trival programs.
Let’s start by instantiating a Java java.util.Date object:
user=> (new java.util.Date)
Mon May 26 10:25:25 PDT 2008
Clojure instantiates the Date object, then calls and displays its toString() method as a visual representation of the object.
To pass arguments to the object’s constructor, just include them in the call to new:
user=> (new StringBuffer "This is the initial value")
This is the initial value
To call an object’s method use the dot (.) form:
user=> (. (new java.util.Date) (toString))
"Mon May 26 11:12:15 PDT 2008"
The dot form uses a dot character (.) as the operator. The second argument is the object whose method will be called. The third argument is a list containing the method name and the method’s arguments, if any:
user=> (. (new java.util.HashMap) (containsKey "key"))
false
Static methods can be called in the same way:
user=> (. Boolean (valueOf "true"))
true
Class and instance fields are accessed in a similar fashion:
user=> (. Integer MAX_VALUE)
2147483647
user=> (. Character TYPE)
char
(Good luck finding an example of a public instance field in the Java standard library)
The difference here is that the field name is not enclosed in parentheses.
Just like in a Java program, Clojure provides the means to import classes into the current context, so that classes do not need to be written out using the fully-qualified syntax:
user=> (import '(java.io FileReader))
nil
user=> (new FileReader "source.txt")
java.io.FileReader@f784d7
There’s a shortcut syntax for this as well:
user=> (import '(java.io FileReader))
nil
user=> (FileReader. "source.txt")
java.io.FileReader@f784d7
Multiple classes within a package can be included, like this:
user=> (import '(java.io File FileReader))
nil
Both the File and FileReader classes are
imported above.
If the classes are in different packages, use this syntax:
user=> (import '(java.io File) '(java.util HashMap))
nil
Or you can use two separate import statements:
user=> (import '(java.io File))
nil
user=> (import '(java.util HashMap))Looping and Iterating
Here are three ways to loop while incrementing an index from 0 to 4 (5 iterations):
user=> (loop [i 0]
(when (< i 5)
(println i)
(recur (inc i))))
0
1
2
3
4
nil
user=> (dorun (for [i (range 0 5)]
(println i)))
0
1
2
3
4
nil
user=> (doseq i (range 0 5)
(println i))
0
1
2
3
4
nil
The first example uses the loop form, which provides the most flexibility, but requires the most syntactical overhead. The second and third examples are examples of iterating over a sequence, which is a more common kind of looping. The dorun and doseq calls suppress the return values of the containing expressions.
Let’s look at the loop form a little closer.
user=> (loop [i 0]
(when (< i 5)
(println "i:" i)
(recur (inc i))))
i: 0
i: 1
i: 2
i: 3
i: 4
nil
In the above example, the temporary symbol i is bound to a value of 0. The when statement checks to see if i is less than 5. If the test passes, the two expressions inside are evaluated. The println expression outputs the value of i. Next, the recur form is evaluated, which instructs the loop to iterate again with a new value for i. The (inc i) is short for (+ i 1).
Without the recur, a loop expression behaves exactly the same as a let expression.
Sequences
Sequences are in a sense, the core of idiomatic Clojure programming. Understand sequences and the forms that work with them, and you will have cleared one of the biggest hurdles in writing significant Clojure programs.
At first glance, a Sequence looks like another data structure. However, a Sequence is not a data structure. It is an interface, or view, into a data structure. A sequence can be derived from a collection. The relation between collection and sequence is similar to the relation between database table and database view.
Clojure’s section on Sequences gives an excellent definition.
Let’s get a sequence from a vector:
user=> (seq [1 2 3])
(1 2 3)
This bit of code doesn’t merely convert the vector into a list. It calls on the vector to produce a sequence of the vector. The REPL (Read, Evaluate, Print, Loop), as part of its ‘Print’ step, uses the sequence to produce a list so that something meaningful can be displayed.
One way to keep the REPL from creating a list from the sequence is to enclose the expression in another expression that doesn’t consume the sequence. For example, a method call of the sequence will not consume the sequence. Take getClass() for instance:
user=> (.getClass (seq [1 2 3]))
clojure.lang.APersistentVector$Seq
What gets returned is an APersistentVector$Seq, which is the class that represents a vector’s sequence.
All of Clojure’s built-in data structures have method to produce a sequence. The sequence interface is formally named clojure.lang.iSeq, or iSeq.
first
Use first to get the first item in a sequence:
user=> (first (seq [1 2 3]))
1
first will also take a vector directly, implicitly converting it into a sequence:
user=> (first [1 2 3])
1
user=> (first ["a" "b" "c"])
"a"
user=> (first '("A" "B" "C"))
"A"
user=> (first '(:a :b :c))
:a
Most of the sequence forms do this implicit conversion, so you can pass any collection that provides an iSeq interface, including all of Clojure’s built-in collection types.
rest
rest produces a sequence that consists of every item of the original sequence, minus the first item.
user=> (rest [1 2 3])
(2 3)
user=> (rest ["a" "b" "c"])
("b" "c")
user=> (rest '("A" "B" "C"))
("B" "C")
user=> (rest [:a :b :c])
(:b :c)
Keep in mind that no new data structure is created. rest only creates a logical list (a sequence). It is up to the caller to create a data structure, if needed. In the examples above, the caller is the REPL, and it does want to collect the sequence into a list, so that it can display something meaningful. It is computationally inexpensive to create a sequence.
cons
cons creates a new sequence by adding the first argument to the beginning of the collection that is the second argument.
user=> (cons 1 [2 3])
(1 2 3)
user=> (cons :a [:b :c])
(:a :b :c)
Again, no data structure is created by cons. The resulting sequence internally consists of separate pointers to the first and second arguments of cons. To the user (the consumer) of the sequence, it appears as one continuous sequence.


Cape Cod Cottage for Rent