@ 2010 by Satish Talim
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 2
Clojure for Beginners
Copyright (c) 2010 Satish Talim http://satishtalim.com/
Warning and Disclaimer
Every effort has been made to make this book as complete and as accurate as possible, but no
warranty of fitness is implied. The information provided is on an "as is" basis. The author shall
have neither liability nor responsibility to any person or entity with respect to any loss or
damages arising from the information contained in this book.
Revised Edition – 27th May 2010 First Edition – May 2010
PLEASE SUPPORT RUBYLEARNING.COM
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 3
Clojure Notes
Contents
Acknowledgements .................................................................................................................................... 8
ABOUT THE EBOOK ................................................................................................................................... 10
Assumptions ............................................................................................................................................................................. 10
Concept and Approach ........................................................................................................................................................ 10
How to Use This Clojure eBook ....................................................................................................................................... 10
About the Conventions Used in This Clojure eBook .............................................................................................. 11
Learn Clojure Online and for Free.................................................................................................................................. 11
INTRODUCTION TO CLOJURE .................................................................................................................... 12
What is Clojure? ...................................................................................................................................................................... 12
GETTING STARTED .................................................................................................................................... 14
Labrepl Download and Installation (for MS Windows)....................................................................................... 14
What's Labrepl? ................................................................................................................................ 14
Downloading and Installing Labrepl (for MS Windows) .................................................................... 14
Starting the REPL ............................................................................................................................... 15
Loading a file in the REPL .................................................................................................................. 16
Clojure Box Download and Installation (for MS Windows) .............................................................................. 16
Test if Clojure Box works ................................................................................................................... 17
Loading a file in Clojure Box .............................................................................................................. 17
NetBeans/Enclojure Download and Installation (for MS Windows) ............................................................ 18
To create a Clojure Project in NetBeans............................................................................................ 19
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 4
To start the REPL in NetBeans ........................................................................................................... 19
Anatomy of the Enclojure REPL Panel ............................................................................................... 19
Syntax .......................................................................................................................................................................................... 19
Comments .................................................................................................................................................................................. 19
Clojure Coding Guidelines & Naming Convention ............................................................................................. 20
Forms ........................................................................................................................................................................................... 21
Symbols ....................................................................................................................................................................................... 21
Vars and Bindings .................................................................................................................................................................. 22
Literals ......................................................................................................................................................................................... 23
Booleans and nil ................................................................................................................................ 23
Numbers ........................................................................................................................................... 23
Characters and Strings ...................................................................................................................... 25
Keywords .......................................................................................................................................... 26
Exercises ..................................................................................................................................................................................... 26
Exercise 1 .......................................................................................................................................... 26
Exercise 2 .......................................................................................................................................... 27
CHARGING AHEAD .................................................................................................................................... 28
A Quick look at Collections ................................................................................................................................................ 28
Lists ................................................................................................................................................... 28
Vectors .............................................................................................................................................. 29
Sets ................................................................................................................................................... 29
Maps ................................................................................................................................................. 30
Some functions on collections .......................................................................................................... 31
Sequences .................................................................................................................................................................................. 32
seq .................................................................................................................................................... 32
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 5
first .................................................................................................................................................... 32
rest .................................................................................................................................................... 33
cons ................................................................................................................................................... 33
next ................................................................................................................................................... 33
conj, into ........................................................................................................................................... 34
range ................................................................................................................................................. 34
repeat ............................................................................................................................................... 34
iterate, take ...................................................................................................................................... 34
concat ............................................................................................................................................... 35
Flow Control ............................................................................................................................................................................. 35
if, if-not ............................................................................................................................................. 36
cond, condp ...................................................................................................................................... 36
when, when-not ................................................................................................................................ 37
do ...................................................................................................................................................... 38
Defining Functions................................................................................................................................................................. 39
Exercise 1 .......................................................................................................................................... 41
Exercise 2 .......................................................................................................................................... 41
Exercise 3 .......................................................................................................................................... 42
Documentation ........................................................................................................................................................................ 43
Using doc .......................................................................................................................................... 43
find-doc ............................................................................................................................................. 43
Documenting a function ................................................................................................................... 44
Clojure API ........................................................................................................................................ 44
CLOJURE AND JAVA ................................................................................................................................... 45
Working with Java ................................................................................................................................................................. 45
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 6
Importing multiple classes ................................................................................................................ 45
Create a Java object .......................................................................................................................... 45
Accessing methods ........................................................................................................................... 46
..chains .............................................................................................................................................. 46
doto .................................................................................................................................................. 47
Accessing static fields ........................................................................................................................ 47
Accessing static methods .................................................................................................................. 47
-> macro ............................................................................................................................................ 47
Exception handling ............................................................................................................................ 48
Some More Examples ....................................................................................................................... 49
Source for a function......................................................................................................................... 49
Inspector ........................................................................................................................................... 49
DIVING INTO CLOJURE .............................................................................................................................. 51
Namespaces .............................................................................................................................................................................. 51
in-ns function .................................................................................................................................... 51
ns ...................................................................................................................................................... 51
More on Bindings ................................................................................................................................................................... 53
let ...................................................................................................................................................... 53
binding .............................................................................................................................................. 54
Echo Server ............................................................................................................................................................................... 55
Port ................................................................................................................................................... 55
Socket ............................................................................................................................................... 56
clojure-contrib library ....................................................................................................................... 56
server-socket API .............................................................................................................................. 56
duck-streams API .............................................................................................................................. 57
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 7
Step 1: Define a namespace .............................................................................................................. 57
Step 2: Define a port ......................................................................................................................... 58
Step 3: Define a function................................................................................................................... 58
Step 4: Start the server ..................................................................................................................... 58
Step 5: Test the Echo Server ............................................................................................................. 59
StructMaps ................................................................................................................................................................................ 59
Refs ................................................................................................................................................................................................ 61
Transactions ............................................................................................................................................................................. 61
A Simple Accounts example .............................................................................................................. 63
Compiling using Clojure Box .......................................................................................................................................... 64
About the Author ...................................................................................................................................... 67
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 8
Acknowledgements
My interest in Clojure was aroused when Michael Kohl organized the first-ever, free, four-
week, online Clojure course on RubyLearning.org –
http://rubylearning.com/blog/2010/03/09/clojure-101-a-new-course/
(for people with some background in Lisp and / or Clojure.)
Having had no previous exposure to Lisp and Clojure, I could not keep up with the others in
the course after the first week. I decided to start making these study notes from the
perspective of a beginner in Lisp and Clojure but with some experience in other programming
languages.
There are a good number of people who deserve thanks for their help and support they
provided, either before or while this eBook is being written, and there are still others whose
help will come after the eBook is released.
I would specially like to thank Baishampayan Ghose, Daniel Solano Gomez and Michael Kohl
for offering suggestions and proofreading these study notes.
The material in these study notes is drawn primarily from the references mentioned below.
My acknowledgment and thanks to all of them.
Clojure Home
http://clojure.org/
Clojure - Functional Programming for the JVM by R. Mark Volkmann –
http://java.ociweb.com/mark/clojure/article.html
Programming Clojure by Stuart Halloway –
http://www.pragprog.com/titles/shcloj/programming-clojure
The Joy of Clojure by Michael Fogus and Chris Houser –
http://www.manning.com/fogus/
Clojure in Action by Amit Rathore –
http://www.manning.com/rathore/
Practical Clojure by Luke Van der Hart –
http://apress.com/book/view/1430272317
Clojure Programming/Concepts –
http://en.wikibooks.org/wiki/Clojure_Programming/Concepts
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 9
Functional Programming with Clojure Screencast by PeepCode –
http://peepcode.com/products/functional-programming-with-clojure
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 10
ABOUT THE EBOOK
Assumptions
These study notes are for absolute beginners in Clojure.
Some previous programming background is essential.
Some parts require knowledge of Java.
The programs in these study notes have been tested using the Clojure 1.1 version.
Since I have a Windows box, I have mentioned the installation of Clojure and other
dependencies for MS Windows only.
Concept and Approach
I have tried to organize this eBook in which each chapter builds upon the skills acquired in the
previous chapter, so that you will never be called upon to do something that you have not
already learned. This eBook not only teaches you how to do something, but also provides you
with the chance to put those morsels of knowledge into practice with exercises. I have
therefore included several exercises, or assignments, in this eBook so that you will have
opportunities to apply your knowledge.
How to Use This Clojure eBook
I recommend that you go through the entire Clojure eBook chapter by chapter, reading the
text, running the sample programs and doing the assignments along the way. There are no
large applications in this book – just small, self-contained sample programs. This will give you
a much broader understanding of how things are done (and of how you can get things done),
and it will reduce the chance of anxiety, confusion, and worse yet, mistakes.
It is best to read this eBook and complete its assignments when you are relaxed and have time
to spare. Nothing makes things go wrong more than working in a rush. And keep in mind that
Clojure and the assignments in this eBook are fun, not just work exercises. So go ahead and
enjoy it.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 11
About the Conventions Used in This Clojure eBook
Explanatory notes (generally provides some hints or gives a more in-depth explanation of
some point mentioned in the text) are shown shaded like this:
This is an explanatory note. You can skip it if you like - but if you do so, you may miss
something of interest!
Any source code in this Clojure eBook, is written like this:
(defn greet
([] (greet " world"))
([name] (str "Hello " name)))
When there is a sample program to accompany the code, the program name is shown like this:
program.clj
Though we would be discussing Clojure 1.1 on the Windows platform, these notes are
appropriate for Linux/Mac users as well.
If you notice any errors or typos, or have any comments or suggestions or good exercises I
could include, please email me at [email protected].
Learn Clojure Online and for Free
If you want to learn Clojure Programming for free, do join the batch at
http://rubylearning.org/
RubyLearning is the first and only site in the world that teaches Ruby and Clojure
Programming for free. Over 30 mentors help you through the learning process – 24x7.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 12
INTRODUCTION TO CLOJURE
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.
http://en.wikipedia.org/wiki/Functional_programming
"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
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 13
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:
1.2 is expected soon.
1.1 (the current version) released in Dec. 2009.
1.0 released in May 2009.
Clojure was first released on October 16, 2007.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 14
GETTING STARTED
Labrepl Download and Installation (for MS Windows)
What's Labrepl?
Labrepl is an environment for exploring the Clojure language. It includes:
a web application that presents a set of lab exercises with step-by-step instructions
an interactive repl for working with the lab exercises
up-to-date versions of Clojure, contrib, incanter, compojure and a bunch of other
libraries to explore
The Labrepl site mentions how one can use Labrepl on other operating systems.
http://github.com/relevance/labrepl
Downloading and Installing Labrepl (for MS Windows)
Download and install Java version 6 - this is a pre-requisite.
http://java.sun.com/javase/downloads/index.jsp
Next, go to the Labrepl site and click on the "Download Source" button on the top of
the page. A .zip file will get downloaded to your computer. Extract this .zip file to
your c: drive. On my computer it created a folder c:\relevance-labrepl-d6b9759.
For Labrepl to work we shall also need Leiningen.
http://github.com/technomancy/leiningen
Leiningen is a build tool for Clojure. Installation of Leiningen on MS Windows is
complicated, because automatic install isn't implemented yet. For MS Windows you
need to download lein.bat script, and put it into the folder c:\leiningen.
http://github.com/technomancy/leiningen/raw/stable/bin/lein.bat
Set your system environment variable "PATH" to include the folder c:\leiningen.
Create a sub-folder c:\leiningen\lib.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 15
Next download leiningen-1.1.0-standalone.jar and copy it to the folder
c:\leiningen\lib.
http://github.com/downloads/technomancy/leiningen/leiningen-1.1.0-
standalone.jar
After this, download the clojure.jar package. A .zip file gets downloaded to your
computer. From this .zip file extract clojure.jar and copy it to the c:\leiningen\lib
folder.
http://code.google.com/p/clojure/downloads/list
Edit lines 14 and 15 of lein.bat to correct the path, namely:
o set LEIN_JAR=c:\leiningen\lib\leiningen-1.1.0-standalone.jar
o set CLOJURE_JAR=c:\leiningen\lib\clojure.jar
Open a new command window and change folder to c:\relevance-labrepl-d6b9759.
Next type lein deps to install all the dependent libraries. This might take some time.
Close the command window.
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-
d6b9759. Next type:
c:\relevance-labrepl-d6b9759> 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, as follows:
user> (println "Hello World")
Hello World
nil
user>
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 16
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.
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
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.
http://java.sun.com/javase/downloads/index.jsp
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.
http://clojure.bighugh.com/
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 17
Note:
You can watch a video of "Install Clojure - ClojureBox".
http://vimeo.com/9219062
Read the post install notes - http://bitbucket.org/shoover/clojure-box/src/tip/post-
install.txt.
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.
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:
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 18
(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
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.
http://java.sun.com/javase/downloads/index.jsp
2. Download and install NetBeans 6.8 (Java SE option).
http://netbeans.org/downloads/index.html
3. Download the latest Enclojure .nbm file.
http://github.com/EricThorsen/enclojure/downloads
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.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 19
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.
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.
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".
http://vimeo.com/9220148
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.
Comments
Open a new REPL and try out whatever we discuss, from now on.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 20
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]])
)
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.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 21
For more details please see the Clojure Library Coding Standards.
http://www.assembla.com/wiki/show/clojure/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)
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.
Symbols
Symbols are used to name things. Symbols name all sorts of things in Clojure:
Functions like str and concat
Clojure does not have operators. Characters like + - * / are just functions
Java classes like java.lang.String and java.util.Random
Namespaces like clojure.core and Java packages like java.lang
Data structures and references.
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
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 22
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
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.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 23
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.
Literals
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.
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.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 24
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) is surprising as 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
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 25
Arbitrary-precision arithmetic
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.
http://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic
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
format
Round off a number to say 2 decimal places:
(format "%.2f" 1.2345) ; => "1.23"
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.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 26
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.
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.
Exercises
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
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 27
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
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
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 28
CHARGING AHEAD
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. By
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.
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.
It may be good to note that lists are singly linked lists.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 29
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.
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"}
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 30
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 organize 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")
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 31
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.
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
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)
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
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)
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 32
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: they generate elements only when they are
actually needed. Clojure sequences are immutable: they never change.
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
first
You can get the first item in a sequence:
(first aseq)
first returns nil if its argument is empty or nil.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 33
An example:
(first [34 23 15]) ; => 34
(first [ ]) ; => nil
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
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.
next
The next function will return the seq of items after the first:
(next aseq)
(next aseq) is equivalent to (seq (rest aseq)).
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 34
An example:
(next [1 2 3 4]) ; => (2 3 4)
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]
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)
repeat
The repeat function repeats an element p n times:
(repeat 5 "p") ; => ("p" "p" "p" "p" "p")
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.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 35
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:
<pre class="brush: clojure">
An usage example:
(take 5 natural-numbers) ; => (0 1 2 3 4)
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)
Flow Control
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 36
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.
cond, condp
cond is like the case statement of Clojure. The general form looks like the following:
(cond & clauses)
Here's an example:
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 37
(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"
when, when-not
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 38
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"
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)
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 39
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.
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
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.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 40
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
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 41
Finally remember that, Clojure function calls are Java method calls.
Exercise 1
Write a method called convert that takes one argument which is a temperature in degrees
Fahrenheit. This method 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
Exercise 2
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:
(= x y) - Here = is the equality function and returns true if x equals y, false if not.
(rem num div) - Here rem gives us the remainder of dividing numerator by
denominator.
and 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.
or macro evaluates exprs one at a time, from left to right. If a form returns a logical
true value, "or" returns that value and doesn't evaluate any of the other expressions,
otherwise it returns the value of the last expression. (or) returns nil.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 42
Exercise 3
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:
zero? returns true if the argument to zero? is zero, else false.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 43
Documentation
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 >
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+")
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 44
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 >
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.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 45
CLOJURE AND JAVA
Working with Java
Note: This section requires you to have knowledge of the Java programming language.
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))
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.
http://richhickey.github.com/clojure/clojure.core-api.html#clojure.core/macroexpand
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 46
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.))
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)
..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:
The .. reads left to right, like Java. The .. macro is great if the result of each
operation is an input to the next.
It is possible to pass arguments in the intermediate function calls.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 47
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=]>
Accessing static fields
(Math/PI) ; => 3.141592653589793
(System/getProperty "java.home") ; => "C:\\Program Files\\Java\\jdk1.6.0_20\\jre"
Accessing static methods
For static methods, you can use (Classname/membername):
(System/currentTimeMillis) ; => 1272362112453
-> 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
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 48
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>
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).
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 49
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"
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>
Inspector
One useful utility built into Clojure is the ability to pop up a Swing app that can inspect a
data structure.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 50
http://richhickey.github.com/clojure/clojure.inspector-api.html
To start using it, type:
(use 'clojure.inspector) ; => nil
You can use the generic inspect function to look at arbitrary objects:
(inspect (System/getProperties))
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 51
DIVING INTO CLOJURE
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.
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.
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
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 52
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))
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 53
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
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.
http://clojure.org/special_forms#let
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 54
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)
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
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 55
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.
Echo Server
We shall build a simple server that accepts network connections and simply echoes back
whatever was sent.
Port
A port is not a physical device, but an abstraction to facilitate communication between a
server and a client.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 56
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.
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.
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.
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:
http://richhickey.github.com/clojure-contrib/server-socket-api.html
(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)
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 57
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:
http://richhickey.github.com/clojure-contrib/duck-streams-api.html
(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.
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.
Step 1: Define a namespace
(ns echo
(:use [clojure.contrib server-socket duck-streams]))
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 58
Step 2: Define a port
(def port 2222)
Our server socket would be listening on this port defined by the port variable.
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))))
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.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 59
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))
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.
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.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 60
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
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 61
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."
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.
http://en.wikipedia.org/wiki/Software_transactional_memory
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
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 62
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:
We could have used any other function (even our own) in place of inc.
The function passed to alter function takes the current value of the ref as the first
argument and must not have side effects as it may be called more than once.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 63
A Simple Accounts example
The following example by Baishampayan Ghose involves a simple account and its transactions.
The comment form in the example explains the usage of this program:
;;; *acc is a temporary var to store the instance
(ns accounts) ; Change the default namespace to 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)))
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 64
Compiling using Clojure Box
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:
Select a namespace for the source files to be compiled, for example, test.test.
Make one of the source files have the same name as the last part of the namespace.
We'll call this the main source file. For example, test.clj.
Create a directory structure that works with swank-clojure-project of Clojure Box.
Open a command window and create the following directory structure
c:\users\talim\myproject\src\test and c:\users\talim\myproject\classes. Close this
command window.
The folder c:\users\talim\myproject\src\test will store the source file namely
test.clj.
Specify the namespace at the top of the main source file and include the :gen-class
namespace directive. For example: (ns test.test (:gen-class)). Clojure has a stand-
alone utility for generating Java classes in the gen-class macro. When code containing
these calls is compiled, it generates byte-code for the specified classes and writes
them into class files.
In the main source file, use the load function to load all the other source files in the
same namespace with relative paths. In our case we do not have any other source file
apart from test.clj.
http://richhickey.github.com/clojure/clojure.core-api.html#clojure.core/load
In each of the other source files, use the in-ns function (explained in the next section)
to set their namespace.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 65
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).
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 66
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.
Prepared exclusively for Clojure 101 Course participants
@ 2010 by Satish Talim Page 67
About the Author
Satish Talim (http://satishtalim.com/) is a senior software consultant based in Pune, India with over 30+ years of I.T. experience. His experience lies in developing and executing business for high technology and manufacturing industry customers. Personally his strengths lie in Business Development and Business Networking apart from new product and solution ideas. Good experience of organization development. Excellent cross disciplinary background in engineering, computer science and management.
He -
Has helped start subsidiaries for many US based software companies like Infonox (http://www.infonox.com/default.shtml - based in San Jose, CA), Maybole Technologies Pvt. Ltd. (http://servient.com/ - Servient Inc. based in Houston, Texas) in Pune, India.
Has been associated with Java / J2EE since 1995 and involved with Ruby and Ruby on Rails since 2005.
also started and manages two very active Java and Ruby User Groups in Pune, India – PuneJava
http://tech.groups.yahoo.com/group/pune-java/
and PuneRuby
http://tech.groups.yahoo.com/group/puneruby/
Is a Ruby Mentor http://rubymentor.rubyforge.org/wiki/wiki.pl?AvailablePureRubyMentors
on rubyforge.org, helping people with Ruby programming.
He lives in Pune, India, with his wife, son and his Labrador Benzy. In his limited spare time he
enjoys travelling, photography and playing online chess.