Clojure Notes Clojure

Buy the eBook

The Clojure for Beginners eBook contains all the topics covered here. The eBook is over 70 pages and is in pdf format. The cost of this eBook is only US$ 7 and is being collected to help me maintain the site and the eBook, and also provide quality content to you. Click on the image below to buy the eBook.

Clojure for Beginners eBook

Table of Contents

0.0 NOTES FOR WHOM?

0.1 Preamble

0.2 Feedback

The site is currently in alpha and I need your help to make it a great community resource, so please let me know if you've got any feedback on how to make this site better. Send in your feedback and suggestions to satishtalim [at] gmail [dot] com.

I can send you a .pdf file of these Clojure Notes. Please email me if interested.

1.0 INTRODUCTION TO CLOJURE

1.1 What is Clojure?

Clojure is a dynamically-typed, functional programming language that runs on the JVM (Java 5 or greater) and provides interoperability with Java.

"A key characteristic of Clojure is that it is a functional language, which means that functions are the fundamental building-block for programs rather than instructions, as is the case in most other programming languages (known as imperative languages). In Clojure, functions are best thought of as more like their counterparts in mathematics – a function is simply an operation that takes a number of parameters (also called arguments), and returns a value. These functions always return the same result when passed the same arguments. Imperative languages perform complex tasks by executing large numbers of instructions, which sequentially modify a program state until a desired result is achieved. Functional languages achieve the same goal through nested function composition – passing the result of one function as a parameter to the next. By composing and chaining function calls, along with recursion (a function calling itself), a functional program can express any possible task that a computer is capable of performing. An entire program can itself be viewed as a single function, defined in terms of smaller functions. The nesting structure determines the computational flow, and all the data is handled through function parameters and return values." - From Practical Clojure.

A major goal of Clojure is managing concurrency. Wikipedia has a great definition of concurrency: "Concurrency is a property of systems in which several computations are executing and overlapping in time, and potentially interacting with each other. The overlapping computations may be executing on multiple cores in the same chip, preemptively time-shared threads on the same processor, or executed on physically separated processors." The primary challenge of concurrency is managing access to a shared, mutable state.

Clojure helps you write correct concurrent programs by emphasizing immutability. Clojure enforces isolating changes in mutable state as either atomic operation with atoms, within a transaction with refs, or asynchronously with agents. Additionally, there are no explicit locks in Clojure, so this common source of deadlock is removed.

Michael Fogus, author of the book "The Joy of Clojure" says that - "Clojure was born out of creator Rich Hickey's desire to avoid many of the complications, both inherent and incidental, of developing concurrent applications using Java and C++. The Java Virtual Machine is an amazingly practical platform -- it is mature, fast, and widely deployed. It supports a variety of hardware and operating systems and has a staggering number of libraries and support tools available, all of which Clojure can take advantage of, thus allowing prospective developers to avoid the costs of maintaining yet another infrastructure while leveraging existing libraries."

The following shows briefly, the release dates for various versions of Clojure:

2.0 GETTING STARTED

There are many options available to download and install Clojure. For options other than MS Windows, please see:

2.1 Option: Labrepl Download and Installation (for MS Windows)

2.1.1 What's Labrepl?

Labrepl is an environment for exploring the Clojure language. It includes:

The Labrepl site mentions how one can use Labrepl on other operating systems.

2.1.2 Downloading and Installing Labrepl (for MS Windows)

2.1.3 Starting the REPL

Interaction with Clojure is often performed at the REPL (Clojure read-eval-print loop). To start a REPL, open a new command window and change folder to c:\relevance-labrepl-c7d2dc1. Next type:

c:\relevance-labrepl-c7d2dc1> script\repl

This starts a new REPL session and you are presented with a simple user=> prompt. It is at this point that REPL waits for user input. The user namespace is the REPL default, like the default package in Java. You should treat user as a scratch namespace for exploratory development.

After user=> type (println "Hello World") and press ENTER:

user=> (println "Hello World")
Hello World
nil
user=>

The second line above, Hello World, is the console output you requested. The third line, nil, is the return value of the call to Clojure's println (the funtion used to display something on the screen).

For a list of all the functions available in the clojure.core API, see - http://richhickey.github.com/clojure/clojure.core-api.html.

If you get your REPL into a state that confuses you, the simplest fix is to close the command window.

2.1.4 Loading a file in the REPL

If you have a block of code that is too large to conveniently type at the REPL, save the code into a file, and then load that file from the REPL. You can use an absolute path or a path relative to where you launched the REPL.

Here's how you would load a file in your REPL:

(load-file file-name)

The load-file function sequentially reads and evaluates the set of forms (more on this later) contained in the file.

A Clojure program is stored in a text file with the extension .clj. Let us load the file test.clj located in the folder c:\users\talim\myproject\src\test:

(load-file  "c:/users/talim/myproject/src/test/test.clj") ; => nil

2.2 Option: Clojure Box Download and Installation (for MS Windows)

Note: If you have installed Labrepl then you can ignore this step.

  1. Download and install Java version 6 - this is a pre-requisite.
  2. Download and install "Clojure Box". Clojure Box is an all-in-one installer for Clojure on Windows. You simply install and run this one thing, and you get a REPL (Clojure read-eval-print loop) and all the syntax highlighting and editing goodies from clojure-mode and Slime, plus all the power of Emacs under the hood.

Note:

2.2.1 Test if Clojure Box works

Interaction with Clojure is often performed at the REPL.

To test whether Clojure works, double-click on the "Clojure Box" icon on your desktop. This starts a new REPL session and you are presented with a simple user=> prompt. It is at this point that REPL waits for user input. The user namespace is the REPL default, like the default package in Java. You should treat user as a scratch namespace for exploratory development.

After user=> type (println "Hello World") and press ENTER:

user=> (println "Hello World")
Hello World
nil
user=>

The second line above, Hello World, is the console output you requested. The third line, nil, is the return value of the call to Clojure's println (the funtion used to display something on the screen).

For a list of all the functions available in the clojure.core API, see - http://richhickey.github.com/clojure/clojure.core-api.html.

If you get your REPL into a state that confuses you, the simplest fix is to kill the REPL with Ctrl-C.

2.2.2 Loading a file in Clojure Box

If you have a block of code that is too large to conveniently type at the REPL, save the code into a file, and then load that file from the REPL. You can use an absolute path or a path relative to where you launched the REPL.

Here's how you would load a file in your REPL:

(load-file file-name)

The load-file function sequentially reads and evaluates the set of forms (more on this later) contained in the file.

A Clojure program is stored in a text file with the extension .clj. Let us load the file test.clj located in the folder c:\users\talim\myproject\src\test:

(load-file  "c:/users/talim/myproject/src/test/test.clj") ; => nil

2.3 Option: NetBeans/Enclojure Download and Installation (for MS Windows)

Note: If you have installed Labrepl or Clojure Box then you can ignore this step.

  1. Download and install Java version 6 - this is a pre-requisite.
  2. Download and install NetBeans 6.8 (Java SE option).
  3. Download the latest Enclojure .nbm file.
    • In NetBeans go to Tools > Plugins. In the dialog click on Downloaded then click the "Add Plugins..." button.
    • Navigate to the location where you saved the NBM file, select it and click the "Open" button.
    • Highlight "Clojure Plugin" and click the "Install" button.
    • Restart the NetBeans IDE.
    • Next, navigate to Tools > Options > Clojure and at the bottom of the screen select clojure-1.1.0 for the Clojure platform. Click the "OK" button.
    • Restart the NetBeans IDE.

2.3.1 To create a Clojure Project in NetBeans

  1. Navigate to File > New Project... Select Categories Clojure and click the "Next" button.
  2. I created a folder C:\ClojureProjects on my hard disk.
  3. I typed the following:
    • Project Name: RL
    • Default namespace: com.rl.hello
    • Project location: C:\ClojureProjects
  4. Click the "Finish" button.

2.3.2 To start the REPL in NetBeans

  1. Right click on the newly created project namely RL, which you should be seeing in the Projects window.
  2. Select "Start Project REPL" in the window that pops up.

2.3.3 Anatomy of the Enclojure REPL Panel

See: http://www.enclojure.org/Anatomy+of+the+Enclojure+Repl+Panel

Note: You can watch a video of "Install Clojure - NetBeans".

2.4 Syntax

Clojure is a Lisp dialect and has a syntax that uses parentheses and prefix notation. For example, in Java one might write foo(a, b, c), whereas in a Lisp dialect this becomes (foo a, b, c). Since the commas are whitespace and Clojure ignores them, it can be simplified further to (foo a b c). Many text editors and IDEs highlight matching parentheses, so it isn't necessary to count them in order to ensure they are balanced.

Clojure is case-sensitive.

2.5 Comments

Open a new REPL and try out whatever we discuss, from now on.

There are two ways in which you can comment in Clojure.

A line comment is:

; This is a single line Clojure comment

For block comments:

(comment text)

It should be noted that the block comment form above does have a return value, namely nil. So you can't just "comment out" a piece of your code with it, because it still leaves a trace. This form is sometimes used at the end of a source code file to demonstrate usage of an API.

For example, the Clojure inspector library ends with the following comment, demonstrating the use of the inspector:

(comment

(load-file  "src/inspector.clj" )
(refer  'inspector)
(inspect-tree  {:a  1  :b  2  :c  [1  2  3  {:d  4  :e  5  :f  [6  7  8]}]})
(inspect-table  [[1  2  3][4  5  6][7  8  9][10  11  12]])

)

2.6 Clojure Coding Guidelines & Naming Convention

  1. Use two spaces for indentation.
  2. Make your names for functions, vars as descriptive as possible, without being overly verbose.
  3. Use lower-case letters for names.
  4. The names of predicate functions (returning a truthy (everything not nil or false) or falsy (false and nil) should typically end with a question mark (?).
  5. End the name of a function in an exclamation mark (!) if it is destructive.

The obvious exceptions to the guidelines above are when generating Java code, which requires that Java naming conventions be observed.

For more details please see the Clojure Library Coding Standards.

The naming convention in Clojure is to use all lowercase with hyphens separating words in multi-word names, unlike the Java convention of using camelcase.

An example:

(function-name arg1 arg2 arg3)

2.7 Forms

Clojure code is composed of Clojure data. When you run a Clojure program, a part of Clojure called the reader reads the text of the program in chunks called forms and translates them into Clojure data structures. Clojure then compiles and executes the data structures.

A Clojure form is basically just an expression. It's any piece of code that evaluates down to a single value.

The Clojure forms are: symbols, literals (i.e. booleans, nil, numbers, characters, strings, keywords), lists, vectors, maps and sets.

2.8 Symbols

Symbols are used to name things. Symbols name all sorts of things in Clojure:

Symbols cannot start with a number and can consist of alphanumeric characters, plus +, -, *, /, !, ?, ., and _.

You can call a function through a symbol such as println:

(println "Hello Clojure participants") ; => Hello Clojure participants

Rather than calling a function through a symbol, you might choose just to retrieve the function itself. The literal representation of a function at the REPL is just a mangled name:

println

Sometimes you want to refer to the symbol itself, without retrieving whatever it refers to. To do this, you can quote the symbol:

(quote println) ; => println

Quoting is so common that that there is a sugared form: simply put a single quote in front of any symbol to prevent that form from being evaluated:

'println ; => println

2.9 Vars and Bindings

The special form (these are forms evaluated in a special way) def creates a var. If the var did not already exist and no initial value is supplied, the var is unbound. In the code below, x is a symbol which is used to identify the var in the future. At this point, x has no "value", and so we can't refer to it:

(def x) ; => #'user/x
x ; => java.lang.IllegalStateException: var user/x is unbound.

If called with an additional parameter it creates a root binding or rebinds the var in case it was already bound. This binding is like an "invisible" link between the var and the value. For example, the following def creates a var named user/my-var in the namespace user:

(def my-var 10) ; => #'user/my-var

The symbol user/my-var refers to a var that is bound to the value 10. The initial value of a var is called its root binding.

Clojure provides bindings which are like constants in other languages, which are not intended to be changed after a value is assigned. Other threads can then override that binding temporarily. Threads which do not have a thread local binding will inherit the root binding. There are global bindings, thread-local bindings, bindings that are local to a function and bindings that are local to a given form.

The def special form creates a global binding and optionally gives it a "root value" that is visible in all threads unless a thread-local value is assigned.

In Clojure, the object that your var is referring to can't change. If you want your var to refer to a different value, you have to rebind it to a new object, a new value. Although vars can be rebound, it is generally not done in a program except to create thread-local bindings.

2.10 Literals

2.10.1 Booleans and nil

Clojure’s rules for booleans (true and false) are easy to understand:

  1. true is true, and false is false.
  2. In addition to false, nil (meaning 'nothing/no-value'- represents Java null) also evaluates to false when used in a boolean context.
  3. Other than false and nil, everything else evaluates to true in a boolean context.

2.10.2 Numbers

A number consists of only the digits 0-9, a decimal point '.', a sign ('+' or '-'), and an optional 'e' for numbers written in exponential notation. In addition to these elements, numbers in Clojure can take either octal or hexadecimal form and also include an optional 'M' (this is used to explicitly create a BigDecimal).

Clojure supports the following numeric types: integer, floating point, ratio.

Integers comprise the whole number set, both positive and negative. That is, any number starting with an optional sign or digit followed exclusively by digits is considered and stored as an integer. Integers in Clojure can theoretically take an infinitely large value, although in practice the size is limited by the memory available.

Floating point numbers are of the form of some number of digits, a decimal point, followed by some number of digits. However, floating point numbers can also take an exponential form where a significant part is followed by an exponent part separated by a lower or uppercase 'E'.

0x7F ; => hexadecimal number whose value is 127
0177 ; => octal number whose value is 127
11.7e-3 ; => 0.0117
(+ 1 2 3 4) ; => 10
(/ 22 7) ; => 22/7
200/5 ; => 40

In the code above, we first use the + function to add the numbers 1, 2, 3 and 4. The result of (/ 22 7) can be surprising - Clojure has a built in clojure.lang.Ratio type. Using ratios help avoid inaccuracies in long computations. Ratios are represented by an integer numerator and denominator. Also observe that the ratio 200 / 5 will resolve to the integer 40.

Lets first try a computation of (1/5 * 5/1) as floating point. Later we try the same with Ratio.

(def x (/ 1.0 5.0))
(def y (/ 5.0 1.0))

(* x y) ; => 1.0

(def p (* x x x x x x x x x x))
(def q (* y y y y y y y y y y))

(* p q) ; => 1.0000000000000004

The value of (* p q) above is 1.0000000000000004 instead of 1 which is what we want. This is due to the inaccuracies of x and y multiplying as we create p and q. You really don't want such calculations happening in your financial transactions!

The same done with ratios below:

(def x (/ 1 5))
(def y (/ 5 1))

(* x y) ; => 1

(def p (* x x x x x x x x x x))
(def q (* y y y y y y y y y y))

(* p q) ; => 1

Using a floating point literal instead, we get:

(/ 22.0 7) ; => 3.142857142857143

2.10.2.1 Arbitrary-precision arithmetic Java

In Clojure, we can do arbitrary-precision arithmetic - a technique whereby calculations are performed on numbers whose digits of precision are limited only by the available memory of the host system. Clojure relies on Java's BigDecimal class for arbitrary-precision decimal numbers and on Java's BigInteger class for arbitrary-precision integers.

If you are doing arbitrary-precision math, append M to a number to create a BigDecimal literal:

(+  1  (/  0.00001  1000000000000000000)) ; => 1.0
(+  1  (/  0.00001M  1000000000000000000)) ; => 1.00000000000000000000001M

Clojure objects are Java objects and you can use Java's Reflection API methods such as class, ancestors, and instance? to reflect against the underlying Java object model.

(class (+  1  (/  0.00001M  1000000000000000000))) ; => java.math.BigDecimal

Clojure's approach to arbitrary-sized integers is simple: just don't worry about it. Clojure will automatically upgrade to Long or BigInteger when you need it. Try creating some small and large integers, and then inspect their class:

(class  (*  100  100  100)) ; => java.lang.Integer
(class  (*  9000  9000  9000)) ; => java.lang.Long
(class  (*  9000  9000  9000  9000  9000  9000  9000  9000)) ; => java.math.BigInteger

2.10.2.2 format

Round off a number to say 2 decimal places:

(format "%.2f" 1.2345) ; => "1.23"

2.10.3 Characters and Strings

Clojure character literals are preceded by a backslash. Their literal syntax is \{letter}, where letter can be a letter or the name of a character: backspace, form-feed, newline, return, space, or tab. These yield the corresponding characters.

Clojure strings are Java strings. They are immutable, and have access to all the underlying Java methods. They are delimited by double quotes ("), and they can span multiple lines. Strings are sequences of characters. The function concat returns a list of character literals, of the elements in the supplied strings:

(concat "Hello" " World")  ; => (\H \e \l \l \o \space \W \o \r \l \d)

Clojure's str is a function call that concatenates an arbitrary list of arguments into a string:

(str  \h  \e  \l  \l \o \space  \w  \o  \r  \l  \d) ; => "hello world"
(str "Hello" " " "World") ; => "Hello World"

Standard Java escape characters are supported. If you want to put a double quote inside a string then you have to escape the double quote. The backslash is the escape character:

(println "She replied: \"Hello\" to my greetings.") ; => She replied: "Hello" to my greetings.

2.10.4 Keywords

A keyword is like a symbol, except that keywords begin with a colon (:). Keywords resolve to themselves:

:foo ; => :foo

The fact that keywords resolve to themselves makes keywords useful as keys.

2.11 Exercises

2.11.1 Exercise 1

Write a Clojure program that displays how old I am, if I am 979000000 seconds old.

Sample solution:

(println "You are" (/ 979000000 60.0 60 24 365) "years old")  ; => You are 31.04388635210553  years old
; Note that println automatically added a space between its arguments

We can improve upon the above program. It's always better to perform the calculation using exact numbers and then coerce the result if needed (we use float in the example below). This is an advantage which Clojure offers when compared to other languages; you can perform calculations with exact numbers instead of floating point approximations. A better solution would be:

(println "You are" (float (/ 979000000 60 60 24 365)) "years old") ; => You are 31.043886  years old

2.11.2 Exercise 2

Write a Clojure program that tells you how many minutes there are in a year (do not bother right now about leap years etc.).

Sample solution:

(println  "There are" (* 60 24 365) "minutes in a year") ; => There are  525600 minutes in a year

3.0 CHARGING AHEAD

3.1 A Quick look at Collections

Clojure provides the collection types list, vector, set and map. The Clojure collection types are immutable, heterogeneous and persistent. By immutable it means that their contents cannot be changed. By heterogeneous it means that they can hold any kind of object. Bt persistent it means that when a new version of a collection is created by adding or removing something from it, the new version shares structure with the old one. The old version will be accessible only when we hold a reference to its head otherwise it will be garbage collected.

3.1.1 Lists

Lists are written with parenthesis. Lists are the traditional LISP singly linked lists. Lists can contain items of any type, including other collections:

; Empty list
() ; => ()
(class ()) ; => clojure.lang.PersistentList$EmptyList

'(a b c) ; => (a b c)
(class '(a b c)) ; => clojure.lang.PersistentList

A list is "just data," but it is also used to call functions. They are ideal when new items will be added to or removed from the front. Lists are not efficient for finding items by index.

An example of a list whose first item names a Clojure function:

(+  1  2)

In Clojure, data and code have the same representation. (a b c) is a call to a function named a with arguments b and c. To make this data instead of code, the list needs to be quoted. '(a b c) or (quote (a b c)) is a list of the values a, b and c.

3.1.2 Vectors

Vectors are essentially like dynamically-sized arrays. Vectors store a series of values like lists do and can be used like lists, except that they can be indexed by integers. Vectors are written with square brackets:

[1 2 3] ; => [1 2 3]

(class [1 2 3]) ; => clojure.lang.PersistentVector

[ ] ; => [ ]
(class [ ]) ; => clojure.lang.PersistentVector

Vectors are ideal when new items will be added to or removed from the back. Vectors are efficient for finding or changing items by index i.e. vectors are functions of their indices:

; retrieve an element by its index
(["hello" "world" 1 2 3] 1) ; => "world"

Note: Unless the list characteristic of being more efficient at adding to or removing from the front is significant for a given use, vectors are typically preferred over lists. This is mainly due to the vector syntax of [...] being a bit more appealing than the list syntax of '(...). It doesn't have the possibility of being confused with a call to a function, macro or special form.

3.1.3 Sets

Sets are collections of unique items. Sets are zero or more forms enclosed in braces preceded by #. The #{} reader macro is only for hash sets:

#{ } ; => #{ }
(class #{ }) ; => clojure.lang.PersistentHashSet

#{:a :b :c} ; => #{:a :b :c}

Sets are preferred over lists and vectors when duplicates are not allowed and items do not need to be maintained in the order in which they were added. Clojure supports two kinds of sets, unsorted and sorted. Hash sets are generally preferred over sorted sets as they are much faster. Sorted sets are important when keeping things sorted is very important. Here are some more ways to create a set:

(sorted-set "Mandy" "Anita" "Rich") ; #{"Anita" "Mandy" "Rich"}
(hash-set "Mandy" "Anita" "Rich") ; #{"Anita" "Mandy" "Rich"}

; duplicates are removed
(hash-set "Rich" "Mandy" "Anita" "Rich") ; #{"Anita" "Mandy" "Rich"}

3.1.4 Maps

Maps are zero or more key/value pairs where both can be any kind of object and enclosed in braces. Maps store unique keys and one value per key. Often keywords are used for map keys:

{ } ; => { }
(class { }) ; => clojure.lang.PersistentArrayMap

{:Ruby  "Matz"  :Clojure  "Hickey"} ; => {:Ruby  "Matz"  :Clojure  "Hickey"}

You can use a map directly, it is not necessary to bind it to a name:

(:a {:a 1, :b 2}) ; => 1

We can use def to save the map into a Clojure var:

(def  inventors  {:Ruby  "Matz"  :Clojure  "Hickey"})

Commas are considered whitespace, and can be used to separate the pairs:

(def  inventors  {:Ruby  "Matz",  :Clojure  "Hickey"})

Maps are functions. If you pass a key to a map, it will return that key’s value, or it will return nil if the key is not found:

(:Clojure inventors) ; => Hickey
(inventors :Java) ; => nil

The keys function returns a sequence of the map's keys:

; Usage: (keys map)
(keys inventors) ; => (:Ruby :Clojure)

The vals function returns a sequence of the map's values:

; Usage: (vals map)
(vals inventors) ; => ("Matz" "Hickey")

3.1.5 Some functions on collections

There are many core functions that operate on all kinds of collections; far too many to describe here. A small subset of them is described next, mostly using vectors and sometimes lists.

3.1.5.1 count function

The count function returns the number of items in any collection.

(count [22 "green" false]) ; => 3

; empty collections correctly return 0
(count '()) ; => 0

3.1.5.2 reverse function

The reverse function returns a sequence of the items in the collection in reverse order.

(reverse [2 42 72]) ; => (72 42 2)

(reverse '(2 42 72)) ; => (72 42 2)

; strings are collections too
(reverse "hello") ; => (\o \l \l \e \h)

3.1.5.3 apply function

The apply function returns the result of a given function when all the items in a given collection are used as arguments.

(apply - [34 23 9])  ; => 2

3.1.5.4 map function

(map f coll)

map takes a source collection coll and a function f, and it returns a new sequence by invoking f on each element in the coll.

(map * [1 2 3 4] [1 2 3 4]) ; => (1 4 9 16)

3.2 Sequences

A sequential collection is one that holds a series of values without reordering them.

A sequence is a sequential collection that represents a series of values that may or may not exist yet. They may be values from a concrete collection, or values that are computed as necessary. A sequence may be empty.

Sequences include Java collections, Clojure-specific collections, strings, streams, directory structures and XML trees. Because so many things are sequences, the sequence library is very powerful. Remember that the sequence library can be used with all collections (lists, vectors, sets, maps ...).

Important: Most Clojure sequences are lazy i.e. they generate elements only when they are actually needed. Clojure sequences are immutable: they never change.

3.2.1 seq

The seq function turns any core collections into something called a seq i.e. the seq function will return a seq on any seq-able collection (coll):

(seq  coll)

seq will return nil if its coll is empty or nil.

An example:

(seq [1 2 3]) ; => (1 2 3)

(seq [ ]) ; => nil

3.2.2 first

You can get the first item in a sequence:

(first  aseq)

first returns nil if its argument is empty or nil.

An example:

(first [34 23 15]) ; => 34

(first [ ]) ; => nil

3.2.3 rest

You can get everything after the first item, in other words, the rest of a sequence:

(rest  aseq)

rest returns an empty seq (not nil) if there are no more items.

An example:

(rest [34 23 15]) ; => (23 15)

(rest [ ]) ; => ()

(class (rest [ ])) ; => clojure.lang.PersistentList$EmptyList

3.2.4 cons

You can construct a new sequence by adding an item to the front of an existing sequence:

(cons  elem  aseq)

An example:

(cons 1 [2 3 4]) ; => (1 2 3 4)

Under the hood, first, rest and cons are declared in a Java interface clojure.lang.ISeq.

3.2.5 next

The next function will return the seq of items after the first:

(next  aseq)

(next aseq) is equivalent to (seq (rest aseq)).

Examples:

(next [1 2 3 4]) ; => (2 3 4)
(next [ ]) ; => nil

3.2.6 conj, into

(conj  coll  element  &  elements)
(into  to-coll  from-coll)

conj adds one or more elements to a collection, and into adds all the items in one collection to another. For lists, conj and into add to the front:

(conj  '(10  20  30)  :a) ; => (:a 10 20 30)

(into  '(10  20  30)  '(:a  :b  :c)) ; => (:c :b :a 10 20 30)

For vectors, conj and into add elements to the back:

(conj  [10  20  30]  :a) ; => [10 20 30 :a]

(into  [10  20  30]  [:a  :b  :c]) ; => [10 20 30 :a :b :c]

3.2.7 range

range produces a sequence from a start to an end, incrementing by step each time. Ranges include their start, but not their end. If you do not specify them, start defaults to zero, and step defaults to 1.

(range  10  20  2) ; => (10 12 14 16 18)

3.2.8 repeat

The repeat function repeats an element p n times:

(repeat  5  "p") ; => ("p" "p" "p" "p" "p")

3.2.9 iterate, take

(iterate  f  x)

iterate begins with a value x and continues forever, applying a function f to each value to calculate the next.

If you begin with 1 and iterate with inc, you can generate the whole numbers:

(take  10  (iterate  inc  1)) ; => (1 2 3 4 5 6 7 8 9 10)

Since the sequence is infinite, you need another new function to help you view the sequence from the REPL.

(take  n  sequence)

take returns a lazy sequence of the first n items from a collection and provides one way to create a finite view onto an infinite collection.

The following example creates a lazy seq of all natural numbers:

(def natural-numbers (iterate inc 0))

An usage example:

(take 5 natural-numbers) ; => (0 1 2 3 4)

3.2.10 concat

The concat function can be used for plain concatenation of any collection:

(concat [22 "green" false] [33 44]) ; => (22 "green" false 33 44)

; the two collections can be of different types
(concat #{22 "green" false} '(33 44)) ; => ("green" false 22 33 44)

3.3 Flow Control

3.3.1 if, if-not

Clojure’s if evaluates its first argument. If the argument is logically true, it returns the result of evaluating its second argument. If you want to define a result for the "else" part of if, add it as a third argument (but this is optional):

(println (if  (<  34  100)  "yes" ))
; => yes

(println (if 0 "Zero  is  true"  "Zero  is  false")) ; => Zero  is  true

If the first argument to if is logically false and you didn't specify an else form, it returns nil:

(if  (<  50000  100)  "yes" )
; => nil

The if-not macro does the inverse of what the if special form does. The general structure of this macro is:

(if-not test consequent alternative?)

Here, if the test is false, the consequent is evaluated, else if it is true and the alternative is provided, it is evaluated instead.

3.3.2 cond, condp

cond is like the case statement of Clojure. The general form looks like the following:

(cond & clauses)

Here's an example:

(def x 10)
(cond
(< x 0) (println "Negative!")
(= x 0) (println "Zero!"))
; => nil

(cond
(< x 0) (println "Negative!")
(= x 0) (println "Zero!")
:default (println "Positive!"))
; => Positive!

As you can see, the clauses are a pair of expressions, each of the form test consequent. Each test expression is evaluated in sequence, and when one returns true, the associated consequent is evaluated and returned. If none return true, nil is returned. If a :default is provided, the associated consequent is evaluated and returned instead.

The general form of condp looks like the following:

(condp pred expr & clauses)

The condp macro is similar to a case statement in other languages. It takes a two parameter predicate (this is mostly = or instance?) and an expression to act as its second argument. After those it takes any number of value/result expression pairs that are evaluated in order. If the predicate evaluates to true when one of the values is used as its first argument then the corresponding result is returned. An optional final argument is the result to be returned if no given value causes the predicate to evaluate to true. If this is omitted and no given value causes the predicate to evaluate to true then an IllegalArgumentException is thrown:

(condp = 1
    1 "Clojure"
    2 "Ruby"
    3 "Java"
    "Sorry, no match")
; => "Clojure"

(condp = 5
    1 "Clojure"
    2 "Ruby"
    3 "Java"
    "Sorry, no match")
; => "Sorry, no match"

3.3.3 when, when-not

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.

(when true "do-this-first" "then-that" "finally this") ; => "finally this"

when-not is the opposite of when, in that it evaluates its body if the test returns false.

(when-not true "do-this-first" "then-that" "finally this") ; => nil

(when-not false "do-this-first" "then-that" "finally this") ; => "finally this"

3.3.4 do

The do form is used to execute a number of operations in sequence. 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:

(do (println "Hello.") (+ 2 2))
Hello.
4

(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.

do is useful when you want to include a sequence of actions in a position where only a single form is expected, e.g. for having various statements in a branch of an if.

Here's a contrived example:

(if (odd? 3) (println "First true form") (println "Second true form (will not print)")) ; => First true form

(if (odd? 3) (do (println "First true form") (println "Second true form (will print)")))
; => First true form
; => Second true form (will print)

if only accepts one form as if and else branch, so if you want to have several statements in either, you'll have to wrap them in a do. In the first statement above, the second true from will not print, since Clojure sees it as the else-branch. In the second it prints, because do is considered one form.

3.4 Defining Functions

The defn macro defines a function. Its arguments are the function name, an optional documentation string, the parameter list (specified with a vector that can be empty) and the function body. The result of the last expression in the body is returned. Every function returns a value, but it may be nil.

(defn my-function
  "returns a String"
  [name]
  (str "Goodbye, " name)) ; concatenation

(println (my-function "Satish")) ; => Goodbye, Satish

Note: If you are wondering how to figure out which function is a macro or not, in your REPL session type:

user=> (:macro (meta #'defn))
true

Function definitions must appear before their first use. Sometimes this isn't possible due to a set of functions that invoke each other. The declare special form takes any number of function names and creates forward declarations that resolve these cases:

(declare function-names)

defn- works just like defn but functions defined with the defn- macro are private and are hardly secure. This means they are only visible in the namespace in which they are defined. It is trivial to access a private var and as such, defn- should not be used as a security measure. You could use defn- to create some helper functions that shouldn't be exposed outside the namespace.

user=> (ns sqr)
(defn- sq [x] (* x x))
(defn sum-of-squares [p q] (+ (sq p) (sq q)))
#'sqr/sum-of-squares

sqr> (sum-of-squares 4 5) ; => 41

sqr> (sq 5)
java.lang.Exception: Unable to resolve symbol: sq in this context

If you call a function with an incorrect number of arguments, Clojure will throw an IllegalArgumentException.

Functions can take a variable number of parameters (note that there are no commas delimiting the function parameters). Optional parameters must appear at the end. They are gathered into a list by adding an ampersand and a name for the list at the end of the parameter list:

(defn  dating  [person & who-all]
(println  person "are dating" (count who-all)  "people." ))

(dating "You" "1" "2" "3") ; => You are dating 3 people.

; dating function called with only the mandatory parameter
(dating "You") ; => You are dating 0 people.

Clojure functions are "first-class" functions i.e. Clojure functions can be stored, passed and returned just as any other piece of data within that language. Thus, Clojure functions can be stored in vars, held in lists and other collection types, be passed as arguments to and even returned as the result of other functions.

Function definitions can contain more than one parameter list and corresponding body. Each parameter list must contain a different number of parameters. This supports overloading functions. Note that overloading of Clojure functions are based on arity (arity refers to the differences in the argument count that a function will accept) and not on type:

(defn greet
    ([] (greet " world"))
    ([name] (str "Hello " name)))

Anonymous functions have no name. These are often passed as arguments to a named function. When an anonymous function is defined using the fn special form, the body can contain any number of expressions.

((fn [x] (+ x 1)) 9) ; => 10

Functions can be bound to a symbol:

(def plus-one
  (fn [x] (+ x 1)))

(plus-one 9) ; => 10

An anonymous function can also be defined in the short way using #(...). The parameters are named %1, %2, and so on. You can also use % for the first parameter.

(#(apply str %1 %2) "Hello" " World") ; => Hello World

Finally remember that, Clojure function calls are Java method calls.

3.4.1 Exercise

Write a function called convert that takes one argument which is a temperature in degrees Fahrenheit. This function should return the temperature in degrees Celsius.

Sample Solution:

(defn convert
  [fahr]
  (float (* (- fahr 32) 5/9))) ; Note the use of Clojure Ratio

(println ( str "The temperature in Celcius = " (convert 75))) ; => The temperature in Celcius = 23.88889

3.4.2 Exercise

Write a method leap-year? It should have as an argument a year value, check whether it's a leap year and then return true or false. A leap year is every 4 years, but not every 100 years, then again every 400 years.

Sample Solution:

(defn leap-year?
  [input-year]
  (or (and (= (rem input-year 4) 0) (> (rem input-year 100) 0)) (= (rem input-year 400) 0)))

(leap-year? 2100) ; => false

Note:

3.4.3 Exercise

Create a divides? predicate that takes a dividend and a divisor, and returns true if divisor evenly divides the dividend:

Sample Solution:

(defn divides?
  "Does divisor divide dividend evenly?"
  [dividend divisor]
  (zero? (rem dividend divisor)))

Note:

3.5 Documentation

3.5.1 Using doc

Nearly all the forms in Clojure have built-in documentation. If you want to read the doc at the REPL, you can just ask for the function’s doc string:

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
user=>

doc will also tell you if a form is implemented as a macro:

user=> (doc and)
-------------------------
clojure.core/and
([] [x] [x & next])
Macro
  Evaluates exprs one at a time, from left to right. If a form
  returns logical false (nil or false), and returns that value and
  doesn't evaluate any of the other expressions, otherwise it returns
  the value of the last expr. (and) returns true.
nil
user=>

3.5.2 find-doc

The find-doc function will search for anything whose doc output matches a regular expression or string you pass in. Example:

(find-doc "list")

Regular expressions in Clojure look like strings prepended by an #. Use a regular expression to find all the find- functions:

(find-doc #"find-\w+")

3.5.3 Documenting a function

Every function can have a doc description (similar to Javadoc) attached to it, like:

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
user=>

3.5.4 Clojure API

Clojure’s complete API is documented online at http://clojure.org/api. The right sidebar links to all functions and macros by name, and the left sidebar links to a set of overview articles on various Clojure features.

4.0 CLOJURE AND JAVA

4.1 Working with Java Java

Note: This section requires you to have knowledge of the Java programming language.

4.1.1 Importing multiple classes

Note: Clojure programs can use all Java classes and interfaces. As in Java, classes in the java.lang package can be used without importing them. Java classes in other packages can be used by either specifying their package when referencing them or using the import function (use import to refer to Java classes in the current namespace).

(import  'java.util.Random)

import also takes a variable number of lists, with the first part of each list being a package name and the rest being names to import from that package:

(import  '(java.util  Random  Locale)
         '(java.text  MessageFormat))

4.1.2 Create a Java object

Assuming that you have used the import form as shown above, we can create a Java object of Random as follows:

(Random.) ; note the .

Note the existence of the (new) special form. The (ClassName.) form is simply a macro for (new ClassName):

(macroexpand '(Date.)) ; => (new Date)

Note: The macroexpand function returns a macro form's expansion.

To use a Random, you will need to save it away somewhere. For now, simply use def to save the Random into a Clojure var:

(import  '(java.util  Random))
(def rnd (Random.))

4.1.3 Accessing methods

Random also has a nextInt( ) method that takes an argument. You can call it by:

(import  '(java.util  Random))
(def rnd (Random.))
(.nextInt rnd 10)

Also, note that (.methodName obj) is a macro for (. obj methodName):

(macroexpand '(.toString (Date.))) ; => (. (Date.) toString)

If you can't remember all the methods in the Random class, you can pass either a class or an instance to javadoc:

(javadoc java.util.Random)

4.1.4 ..chains

The (..) macro chains together multiple member accesses by making each result the this object for the next member access in the chain. Thus looking up an object’s code URL becomes the following:

(..  '(1  2)  getClass  getProtectionDomain  getCodeSource  getLocation)

Note:

4.1.5 doto

Sometimes you don’t care about the results of method calls and simply want to make several calls on the same object. The doto macro makes it easy to make several calls on the same object. For example, use doto to set multiple system properties:

(doto  (System/getProperties)
  (.setProperty  "name"  "Stuart")
  (.setProperty  "favoriteColor"  "blue"))

doto returns the object at the end. This is very useful for Java Swing classes:

(doto (javax.swing.JPanel.) (.setEnabled false) (.setToolTipText "Not available"))
; => #<JPanel javax.swing.JPanel[,0,0,0x0,invalid,disabled,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=]>

4.1.6 Accessing static fields

(Math/PI) ; => 3.141592653589793

(System/getProperty "java.home") ; => "C:\\Program Files\\Java\\jdk1.6.0_20\\jre"

4.1.7 Accessing static methods

For static methods, you can use (Classname/membername):

(System/currentTimeMillis) ; => 1272362112453

4.1.8 -> macro

(import [java.util Date Random])
(Date. (long (.nextInt (Random.)))) ; => #<Date Sat Jan 10 06:37:47 IST 1970>

In the above code, starting from the inside, you:

  1. get a new Random
  2. get the next random integer
  3. cast it to a long
  4. pass the long to the Date constructor

The above is a bit confusing for beginners new to Clojure. You don't have to write inside-out code in Clojure. The -> macro takes its first form, and passes it as the first argument to its next form. The result then becomes the first argument of the next form, and so on. It is easier to read than to describe:

(import [java.util Date Random])
(-> (Random.) (.nextInt) (long) (Date.)) ; => #<Date Sat Jan 10 06:37:47 IST 1970>

4.1.9 Exception handling

All exceptions thrown by Clojure code are runtime exceptions. Java methods invoked from Clojure code can still throw checked exceptions. In Clojure, you are not forced to deal with checked exceptions. You do not have to catch them or declare that you throw them. The try, catch, finally and throw special forms provide functionality similar to their Java counterparts.

Let's look at an example:

(/ 1 0) ; => java.lang.ArithmeticException: Divide by zero

In the above case we see an java.lang.ArithmeticException being thrown. This is a runtime exception which is thrown by the underlying JVM.

The following shows how runtime exceptions like java.lang.ArithmeticException can be handled:

(try (/ 1 0)
      (catch Exception e (prn "in catch"))
      (finally (prn "in finally")))
"in catch"
"in finally"
nil

Note: The pr and prn functions prints the object(s) to the output stream that is the current value of *out*. pr prints the object(s), separated by spaces if there is more than one. By default, pr and prn print in a way that objects can be read by the reader. prn is the same as pr followed by (newline).

4.1.10 Some More Examples

(.toUpperCase "hello") ; => HELLO
(.length "hello") ; => 5

In the next example, let's write a parse helper function:

(defn parse [s]
  (try (Double/parseDouble (.trim s))
       (catch NumberFormatException e nil)))

(parse "22") ; => 22.0
(parse "     23.45   ") ; => 23.45
(parse "asas") ; => nil

In the following example, the display helper function takes a number, rounds it to the nearest Integer (because Integers are prettier), and returns a String:

(defn display [n]
  (str (Math/round (float n))))

(display 22.5) ; => "23"
(display 22/7) ; => "3"

4.1.11 Source for a function

You can use Clojure to tell you the source for a function. To use this functionality, you’ll need to import the repl-utils library:

user=> (use 'clojure.contrib.repl-utils)
nil

user=> (source println)
(defn println
  "Same as print followed by (newline)"
  [& more]
    (binding [*print-readably* nil]
      (apply prn more)))
nil
user=>

4.1.12 Inspector

One useful utility built into Clojure is the ability to pop up a Swing app that can inspect a data structure. To start using it, type:

(use 'clojure.inspector) ; => nil

You can use the generic inspect function to look at arbitrary objects:

(inspect (System/getProperties))

5.0 DIVING INTO CLOJURE

5.1 Namespaces

Clojure partitions things that are named by symbols into namespaces. There is always a current default namespace, initially set to "user", and it is stored in the special symbol *ns*. The "user" namespace provides access to all the symbols in the clojure.core namespace.

Clojure respects Java naming conventions for directories and files, but Lisp naming conventions for namespace names. So a Clojure namespace com.my-app.utils would live in a path named com/my_app/utils.clj. Note especially the underscore/hyphen distinction.

5.1.1 in-ns function

The default namespace can be changed by the in-ns function. Let's create a "notes" namespace:

(in-ns 'notes) ; => #<Namespace notes>

Now you are in the "notes" namespace, and anything you def or defn will belong to "notes". When you create a new namespace with in-ns, the java.lang package is automatically available to you.

5.1.2 ns

The general form of the ns macro is:

(ns name & references)

The default namespace can be changed by the ns macro. The name, as mentioned above, is the name of the namespace being made current. If it doesn't already exist, it gets created. The references that follows the name are optional, and can be one or more of the following – use, require, import, load, gen-class, or load.

The ns macro will create a new namespace that contains mappings for the classnames in java.lang and for the functions in clojure.core.

Note: In order to access items that are not in the default namespace they must be namespace-qualified. This is done by preceding a name with a namespace name and a slash (whereas Java package names are separated from a class name with a period). Use "use" to load and refer Clojure libraries. For example, the round function lives in clojure.contrib.math. In order to make round available in the current namespace, call use on round's namespace:

(use  'clojure.contrib.math) ; => nil

The simple form of use shown above causes the current namespace to refer to all public vars in clojure.contrib.math. This can be confusing, because it does not make explicit which names are being referred to. Remember to pass the :only option to use, listing only the vars you need:

(use  '[clojure.contrib.math  :only  (round)]) ; => nil

Now you can call round without having to qualify its name:

(round  1.6) ; => 2

The ns macro, mentioned earlier, changes the default namespace. It is typically used at the top of a source file. It supports the directives :require, :use and :import (for importing Java classes) that are alternatives to using their function forms. Using these is preferred over using their function forms. Here, symbols become keywords, and quoting is no longer required.

(ns notes
  (:use [clojure.contrib.math :only (gcd, sqrt)])
  (:import (java.text NumberFormat) (javax.swing JFrame JLabel)))

(println (gcd 27 81)) ; => 27
(println (sqrt 7)) ; => 2.6457513110645907
(println (.format (NumberFormat/getInstance) Math/PI)) ; => 3.142

; the code below requires you to have knowledge of the Java programming language
; also see the generated image below
(doto (JFrame. "Hello")
  (.add (JLabel. "Hello, World!"))
  (.pack)
  (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
  (.setVisible true))

Screenshot

5.2 More on Bindings

An example:

(def cnt 1) ; cnt is a global binding

(defn fn1
  []
  (println "Global binding value of fn1 = " cnt))

(fn1) ; Global binding value of fn1 =  1

5.2.1 let

The let special form creates bindings that are local to that form. Its first argument is a vector containing name/expression pairs. The expressions are evaluated in order (i.e. let does its bindings sequentially) and their results are assigned to the names on their left. These bindings can be used in the expressions that follow them in the vector. They can also be assigned to more than once to change their value. The remaining arguments to let comprise the body which is a set of expressions to be evaluated with the new bindings in scope. Functions that are called in the body cannot see the local bindings created by let.

Do check-out the let documentation.

An example:

(def x 1)
(def y 1)
(let [x 2 y x]
  (+ x y)) ; => 4

x ; => 1
y ; => 1

Another example:

(def cnt 1) ; cnt is a global binding

(defn fn1
  []
  (println "Global binding value in fn1 = " cnt))

(defn fn2
  []
  (println "fn2: before let cnt (still global binding) =" cnt)   ; fn2: before let cnt (still global binding) = 1
  (let [cnt 2]                                                   ; creates local binding cnt that shadows global one
    (println "fn2: in let, cnt (now local binding) =" cnt)       ; fn2: in let, cnt (now local binding) = 2
    (fn1))                                                       ; Global binding value in fn1 =  1
  (println "fn2: after let cnt (back to global binding) =" cnt)) ; fn2: after let cnt (back to global binding) = 1

(fn2)

5.2.2 binding

The binding special form is similar to let, but it temporarily gives new, thread-local values to existing global bindings. The new values are seen inside that form and also in functions called from inside it. When the binding form exits, the bindings revert to their previous values.

An example:

Observe below that binding does its bindings in parallel.

(def x 1)
(def y 1)
(binding [x 2 y x]
  (+ x y)) ; => 3
x ; => 1
y ; => 1

Another example:

(def cnt 1) ; cnt is a global binding

(defn fn1
  []
  (println "Global binding value in fn1 = " cnt))

(defn fn3
  []
  (println "fn3: before binding cnt (still global binding) =" cnt)                    ; fn3: before binding cnt (still global binding) = 1
  (binding [cnt 3]                                                                    ; same global binding with new, temporary value
    (println "fn3: in binding, cnt (global binding value temporarily changed) =" cnt) ; fn3: in binding, cnt (global binding value temporarily changed) = 3
    (fn1))                                                                            ; Global binding value in fn1 =  3
  (println "fn3: after binding cnt (value of global binding reverted back) =" cnt))   ; fn3: after binding cnt (value of global binding reverted back) = 1

(fn3)

Symbols that are intended to be bound to new, thread-local values using binding have their own naming convention. These special symbols have names that begin and end with an asterisk. People sometimes refer to the asterisks as "earmuffs".

For example, Clojure uses dynamic binding for thread-wide options such as the standard I/O streams *in*, *out* and *err*. The predefined, special symbols *in*, *out* and *err* are set to stdin, stdout and stderr by default. Functions that use these bindings are affected by their values. For example, binding a new value to *out* changes the output destination of the println function.

Guideline: As far as possible use let. Use binding when you need a thread-local version of a var.

5.3 Echo Server

We shall build a simple server that accepts network connections and simply echoes back whatever was sent.

5.3.1 Port

A port is not a physical device, but an abstraction to facilitate communication between a server and a client.

Ports are described by a 16-bit integer value. Hence, a machine can have a maximum of 65536 port numbers (ranging from 0 to 65535). The port numbers are divided into three ranges: the Well Known Ports, the Registered Ports, and the Dynamic and/or Private Ports. The Well Known Ports are those from 0 through 1023 (for example, port no. 80 is for http, port no. 25 is for smtp and so on). The Registered Ports are those from 1024 through 49151. The Dynamic and/or Private Ports are those from 49152 through 65535.

5.3.2 Socket

A socket is not a physical device but an abstraction. It represents a single connection between two network applications. These two applications normally run on different computers, but sockets can also be used for inter-process communication on a single computer. Applications can create multiple sockets for communicating with each other. Sockets are bidirectional, meaning that either side of the connection is capable of both sending and receiving data.

5.3.3 clojure-contrib library

The user contributions library, clojure.contrib, is a collection of namespaces each of which implements features that may be useful to a large part of the clojure community. Some parts of clojure.contrib may migrate into clojure.core if they prove to be so generally useful.

See the clojure.contrib API here - http://richhickey.github.com/clojure-contrib/index.html.

5.3.4 server-socket API

To build this simple server, we shall make use of the server-socket API from the clojure.contrib library. We shall use the following from this API:

(ns your-namespace
  (:require clojure.contrib.server-socket))

(create-server port fun)

The above code creates a server socket on port. When accepting a connection, a new thread is created which calls:

(fun input-stream output-stream)

5.3.5 duck-streams API

We shall also make use of the duck-streams API from the clojure.contrib library. We shall use the following from this API:

(ns your-namespace
  (:require clojure.contrib.duck-streams))

This library defines "duck-typed" I/O utility functions for Clojure. The 'reader' and 'writer' functions will open and return an instance of java.io.BufferedReader and java.io.PrintWriter, respectively, for a variety of argument types - filenames as strings, URLs, java.io.File's, etc. 'reader' even works on HTTP URLs.

5.3.5.1 spit function

Let's make a little diversion. We shall have a look at the spit function from the clojure.contrib library. This function is not used in the Echo Server.

Usage:

(spit f content)

Opens f with writer, writes content, then closes f.

Here's an example:

(use  '[clojure.contrib.duck-streams  :only  (spit)])
(spit  "rubylearning.out"  "Hello  RubyLearning participants.")

You should now find a file at rubylearning.out with contents Hello RubyLearning participants.

5.3.6 Step 1: Define a namespace

(ns echo
  (:use [clojure.contrib server-socket duck-streams]))

5.3.7 Step 2: Define a port

(def port 2222)

Our server socket would be listening on this port defined by the port variable.

5.3.8 Step 3: Define a function

Our function handle-client takes two arguments named in and out. In this case it will be streams attached to the client's socket.

binding binds names to new values temporarily. in and out are the default streams that the standard IO functions read from (stdin) and write to (stdout). But within the body of this binding block, they will now refer to readers and writers for the client socket. This way we can use functions like read-line and println to communicate with the client. In fact, in our block we read a line and print it out. loop begins the loop and recur returns to the start of the loop.

(defn handle-client [in out]
  (binding [*in* (reader in)
            *out* (writer out)]
    (loop []
      (println (read-line))
      (recur))))

5.3.9 Step 4: Start the server

To start the server, type the following in your REPL:

(def server (create-server port handle-client))

Finally we call create-server with two arguments - the port number and the function we want to handle the client connections. We keep this in the server var. A lot of the concurrency issues are handled by Clojure inside the create-server function. We don't have to worry about firing-up threads or doing other kinds of listeners. It will handle that under the covers. So that's it for a simple echo server. Our echo server is running at port 2222 on localhost.

Here's the complete code of our Echo Server:

(ns echo
  (:use [clojure.contrib server-socket duck-streams]))

(def port 2222)

(defn handle-client [in out]
  (binding [*in* (reader in)
                  *out* (writer out)]
    (loop []
       (println (read-line))
       (recur))))

(def server (create-server port handle-client))

5.3.10 Step 5: Test the Echo Server

Open a command window and use Telnet to connect to our Echo Server:

telnet localhost 2222

Now anything I type in will be echoed back.

5.4 StructMaps

The defstruct macro is used to define a StructMap:

(defstruct account-struct  :name :balance)

The structure field names of type keyword or symbols are automatically usable as functions to access fields of the structure. This is possible as structures are maps and this feature is supported by maps. This is not possible for other types of field names such as strings or numbers. It is quite common to use keywords for field names for structures due to the above reason.

The object returned by defstruct is what is called the structure basis. This is not a structure instance but contains information of what the structure instances should look like.

New instances of a given StructMap are created using struct. Values must be specified in the same order as their corresponding keys were specified when the StructMap was defined. Values for keys at the end can be omitted and their values will be nil:

(def account (struct account-struct "Michael" 5000))

account ; => {:name "Michael", :balance 5000}

(:name account) ; => "Michael"

New keys not specified when the StructMap was defined can be added to instances. However, keys specified when the StructMap was defined cannot be removed from instances:

(def account-sm (struct-map account-struct  :title "programmer" :name "Daniel" :balance 4000))

account-sm ; => {:name "Daniel", :balance 4000, :title "programmer"}

As structures are maps, new fields can also be added to structure instances using assoc.

account ; => {:name "Michael", :balance 5000}

(def account-new (assoc account :title "programmer")) ; => {:name "Michael", :balance 5000, :title "programmer"}

(:title account-new) ; => "programmer"

assoc can also be used to "update" a structure:

account ; => {:name "Michael", :balance 5000}

(assoc account :balance 6000) ; => {:name "Michael", :balance 6000}

account ; => {:name "Michael", :balance 5000} ; note that 'account' is immutable and did not change

dissoc can be used to remove these instance specific keys. Note however that struct base keys cannot be removed.

account-new ; => {:name "Michael", :balance 5000, :title :address}

(def account-new2 (dissoc account-new :title)) ; this works as :title are instance specific keys

account-new2 ; => {:name "Michael", :balance 5000}

(dissoc account-new2 :balance) ; this fails. base keys cannot be dissociated
; => java.lang.Exception: Can't remove struct key

5.5 Refs

Most objects in Clojure are immutable. When you really want mutable data, you must be explicit about it, such as by creating a mutable reference (ref) to an immutable object. You create a ref with this:

(ref  initial-state)

For example, you could create a reference to your current residential address:

(def current-addr (ref "Vasant Villa, 759/43 Deccan Gym., Pune"))

The ref wraps and protects access to its internal state. To read the contents of the reference, you can call deref:

(deref current-addr) ; => "Vasant Villa, 759/43 Deccan Gym., Pune"

The deref function can be shortened to the @ reader macro:

@current-addr ; => "Vasant Villa, 759/43 Deccan Gym., Pune"

An address is an immutable entity. It doesn't change into another address when you move to a new address. But your current address is a reference to an entity, and it can change.

In Rich Hickey's words - "In languages like Java and C++ there is a conflation of the concept of an identity with its state, which is a value. Clojure deals primarily with values. Refs are a way to create identities, which can point to different values (have different states), over time. As such, unlike the private state of a Java object, the value of a ref is not ‘owned by’ the ref."

5.6 Transactions

Because refs are mutable, you must protect their updates. In many languages, you would use a lock for this purpose. In Clojure, you can use a transaction (STM). Refs can only be modified inside a transaction. Transactions are wrapped in a dosync. You can change where a reference points with ref-set.

The dosync macro starts a transaction that continues while the expressions in its body are evaluated. The ref-set function changes the in-transaction value of a ref and returns it. It must be called inside a transaction, otherwise an IllegalStateException is thrown. The change will only be visible outside the transaction if and when the transaction commits. This happens when a dosync exits without an exception being thrown:

(ref-set current-addr  "13 Kanchan-Shri, Shirole Road, Pune") ; => java.lang.IllegalStateException

; The current-addr reference will now refer to a different address
(dosync
  (ref-set current-addr "13 Kanchan-Shri, Shirole Road, Pune")) ; => "13 Kanchan-Shri, Shirole Road, Pune"

@current-addr ; => "13 Kanchan-Shri, Shirole Road, Pune"

The alter function is used for changes that must be made in a specific order. The commute function is used for changes whose order is not important and can be performed in parallel. Both functions must be called inside a transaction.

(dosync (alter current-addr (fn [_] "13 Kanchan-Shri, Shirole Road, Pune"))) ; => "13 Kanchan-Shri, Shirole Road, Pune"

Note: In the example above we have used an underscore (_), which is used as a placeholder for function parameters that won't be used and therefore don't need a name.

Another example: Suppose we want to add one to the value of a ref named counter. This could be implemented as follows, using inc for the update function:

(def counter (ref 0))
(dosync (alter counter inc)) ; => 1

Note:

5.6.1 A Simple Accounts example

The following example involves a simple account and its transactions. The comment form in the example explains the usage of this program:

;;;    accounts.clj
;;;    *acc is a temporary var to store the instance
;;;    Author: Baishampayan Ghose


; Change the default namespace to accounts
(ns accounts)


; Create a structure basis called acct-struct
(defstruct acct-struct :name :balance)


(defn make-account
  "Create a new account"
  [acct-name op-balance]
  ;; op-balance should be stored in a ref so that we can modify it in
  ;; a concurrent manner
  ;; Use struct to create a new instance of StructMap
  (struct acct-struct acct-name (ref op-balance)))


(defn account-balance
  "Get the balance from an account"
  [acc]
  ;; read the contents of the reference with @
  @(:balance acc))


(defn deposit
  "Deposit amount into acc"
  [acc amount]
  (dosync
   (commute (:balance acc) + amount)))


(def *min-bal* 500)


(defn withdraw
  "Withdraw amount from acc. Minimum balance is 500"
  [acc amount]
  (dosync
   (let [curr (:balance acc)]
     (if (> (- @curr amount) *min-bal*)
       (alter curr - amount)
       :insufficient-funds))))


(comment

(def *acc (make-account "Satish Talim" 5000))
(deposit *acc 500)
(account-balance *acc)
(withdraw *acc 20)
(account-balance *acc)

(binding [*min-bal* 0]
  (withdraw *acc 5000))

)

5.7 Compiling using Clojure Box Java

When Clojure source files are executed as scripts, they are compiled to Java bytecode at runtime. These .class files can be used in Java applications.

Shawn Hoover, the creator of Clojure Box has this to say:

"I made Clojure Box mainly so people would have a quick and easy REPL. Of course all of Emacs is there and people will want to use it. Unfortunately swank-clojure is not as refined for compilation and running projects like Enclojure might be (I would actually recommend Enclojure over Clojure Box for beginners these days).

The bottom line is you can achieve what you want, but it takes some manual steps. Note that M-x means to type Alt-x. C-x is Control-x. C-w is Control-w. M-x allows you to execute a command by typing a command name. After typing M-x, you are presented with a prompt to type a command name - make-directory, cd, swank-clojure-project, and shell are commands you can type at that prompt. Some commands then present an additional prompt related to the command."

Let us write a test.clj Clojure program as follows:

Here's the code for the test.clj program:

(ns test.test (:gen-class))

(defn -main
  ([greetee]
  (println (str "Hello " greetee "!")))
  ([] (-main "world")))

Now at the REPL, type the following:

M-x cd c:\users\talim\myproject

So the above "M-x cd c:\users\talim\myproject" means:
Type Alt-x
At the prompt type cd ENTER
At the next prompt type c:\users\talim\myproject and ENTER
Next type:

M-x swank-clojure-project c:\users\talim\myproject

So the above "M-x swank-clojure-project c:\users\talim\myproject" means:
Type Alt-x
At the prompt type swank-clojure-project ENTER
At the next prompt (Project root:) type the name of the directory that contains src\test\test.clj i.e. c:\users\talim\myproject and ENTER.
You probably already have a slime repl running, so it will say "Buffer has a running process; kill it? (yes or no)". Type yes to kill the existing repl and start a new one that has the classpath set up based on your project directory structure (the classpath must have the clojure.jar installed with Clojure Box, your src directory, and your classes directory for compilation to work--these things are all set up automatically by the swank-clojure-project function).

At the REPL, type:

(compile 'test.test)
; => test.test

To execute the program, type the following at the REPL:

M-x shell ENTER

At the REPL, you will see: c:\users\talim\myproject.

A separate .class file is produced for each function. They are written under the "classes" directory in a directory structure that corresponds to their namespace. If the compiled namespace has a function named -main, it can be run as a Java application. Command-line arguments are passed as arguments to that function.

At the REPL type:

java -cp "c:\Program Files\Clojure Box\lib\clojure.jar";classes test.test
; => Hello world!

That should work.

References