Clojure

Clojure is simple, easy, fun, and very cool. Some have said that Clojure—or a language very much like it—is the future of programming languages.

Overview

Clojure:

Links

Important and useful information about Clojure itself:

Cultural readings:

Videos:

What is so great about Clojure being in the Lisp family?

Lisp is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use Lisp itself a lot. —Eric S. Raymond

Getting Started

Install Clojure by downloading the latest version from the Clojure download page or use your favorite package manager (e.g., brew install clojure should just work on a Mac). Now you can:

Writing simple scripts

Make a file called hello.clj that looks like this:

hello.clj
(println "Hello, world")

And run it:

$ clojure -M hello.clj
Hello, world

Another simple script:

triple.clj
; This script prints all integer Pythagorean triples for values <= 100.

(doseq [c (range 1 101) b (range 1 c) a (range 1 b)]
  (if (= (+ (* b b) (* a a)) (* c c))
    (printf "(%d,%d,%d)\n" a b c)))
$ clojure -M triple.clj
(3,4,5)
(6,8,10)
(5,12,13)
(9,12,15)
.
.
.
(65,72,97)
(60,80,100)
(28,96,100)

Another simple script, this time using command line arguments:

gcd.clj
; This script prints the gcd of its two command line arguments

(defn gcd [x y]
  (if (= y 0) x (gcd y (mod x y))))

(println
  (gcd
    (read-string (first *command-line-args*))
    (read-string (second *command-line-args*))))
$ clojure -M gcd.clj 52 91
13

Using interactive mode

There is a cheap REPL:

$ clojure
$ user=> (+ 8 7)
15
$ user=> (/ 8 7)
8/7
$ user=> (type (/ 8 7))
clojure.lang.Ratio

Now try to hit the up arrow key to bring back the last command. Ooops. Or type a line and try using the right and left arrow keys. Pretty annoying, huh?

Leiningen

You'll want to use Leiningen to do anything with Clojure. Follow the instructions on its main project page on github for installation. Now you can fire off a repl using the lein script.

$ lein repl
user=> (/ 22 7.0)
3.142857142857143
user=> (* (/ 3 4) (/ 2 5))
3/10
user=> (defn fact [a] (if (<= a 1) 1 (* (fact (- a 1)) a)))
#'user/fact
user=> (fact 40)
ArithmeticException integer overflow  clojure.lang.Numbers.throwIntOverflow
(Numbers.java:1388)
user=> (defn fact [a] (if (<= a 1N) 1N (* (fact (- a 1N)) a)))
#'user/fact
user=> (fact 40)
815915283247897734345611269596115894272000000000
user=> (type \k)
java.lang.Character
user=> (type :k)
clojure.lang.Keyword
user=> (type 'k)
clojure.lang.Symbol

Learning By Example

Here are few example evaluations in the REPL to get you warmed up. After you check these examples out, please go spend some time with the Cheatsheet and the Core QuickRef.

Symbols

user=> (type 'k)
clojure.lang.Symbol
user=> (type k)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: k in
this context, compiling:(NO_SOURCE_PATH:1)

That's because things are evaluated: the value of `k is the symbol k, but when we just write k we mean the value associated with k. Confused yet? We would like to use recursion, but we all know the gt; (def k 5) #'user/k user=> 'k k user=> k 5

Numbers

You'll recognize some of the numeric types from Java, but Clojure does add some new ones.

user=> (type 9)
java.lang.Long
user=> (type 9223372036854775807)
java.lang.Long
user=> (type 9223372036854775808)
clojure.lang.BigInt
user=> (type 579347593875938474772983477234283929398762781091283)
clojure.lang.BigInt
user=> (type 7N)
clojure.lang.BigInt
user=> 2.35E234
2.35E234
user=> (type 2.35E234)
java.lang.Double
user=> 2.35E999
Double/POSITIVE_INFINITY
user=> 2.35E999M
2.35E+999M
user=> (type 2.35E999M)
java.math.BigDecimal

Strings

user=> (str "94" 2 6 " dogs")
"9426 dogs"
user=> (format "It was %d %s" 40 "degrees")
"It was 40 degrees"
user=> (count "привет")
6
user=> (subs "Hello" 2 4)
"ll"
user=> (subs "I'm hungry" 4 7)
"hun"
user=> (split "192.168.1.1" #"\.")
CompilerException java.lang.RuntimeException: Unable to resolve symbol: split in this
context, compiling:(NO_SOURCE_PATH:1)
user=> (clojure.string/split "192.168.1.1" #"\.")
["192" "168" "1" "1"]
user=> (use 'clojure.string)
nil
user=> (split "192.168.1.1" #"\.")
["192" "168" "1" "1"]

Collections

Clojure has four basic collection types:

Clojure collections are immutable and persistent. Adding or removing produces a new object, rather than mutating the collection. They use structural sharing, are efficient, and inherently thread-safe.

The following functions work on all collection types:

Lists

A Lists is a sequence in which count is Θ(1) and conj adds to the front.

Lists are immutable, of course:

user=> (def x (list 1 2 3 4 5))
#'user/x
user=> x
(1 2 3 4 5)
user=> (conj x 100)
(100 1 2 3 4 5)
user=> x
(1 2 3 4 5)

Please make a point to fully understand first, rest, and cons. They are part of Clojure's Lisp heritage (actually List uses the terms car, cdr, and cons, but that's just life).

user=> (def dogs (list 'sparky 'spot 'spike 'rex))
user=> (first dogs)
sparky
user=> (rest dogs)
(spot spike rex)
user=> (cons 'max dogs)
(max sparky spot spike rex)
user=> dogs
(sparky spot spike rex)

Vectors

A Vector is a collection of values indexed by contiguous integers. The conj operation adds to the end.

user=> (def dogs ['sparky 'spot 'spike 'max])
user=> (type dogs)
clojure.lang.PersistentVector
user=> (count dogs)
4
user=> (conj dogs 'rex)
[sparky spot spike max rex]
user=> (peek dogs)
max
user=> (get dogs 2)
spike

Sets

A Set is a collection of unique elements.

user=> (def dogs #{'sparky 'spot 'spike 'max})
user=> dogs
#{sparky max spot spike}
user=> (= dogs #{'spike 'max 'spot 'sparky})
true
user=> (conj dogs 'rex)
#{rex sparky max spot spike}
user=> (count dogs)
4
user=> (disj dogs 'sparky)
#{max spot spike}
user=> (contains? dogs 'spot)
true
user=> (contains? dogs 'sport)
false

There are hashed and sorted varieties of sets:

user=> (vec (hash-set 5 8 10 2 1 6 -5))
[1 2 -5 5 6 8 10]
user=> (vec (sorted-set 5 8 10 2 1 6 -5))
[-5 1 2 5 6 8 10]

Maps

A Map is a collection mapping keys to values.

user=> (def capitals {:ca "sacramento" :hi "honolulu" :ak "juneau"})
#'user/capitals
user=> (type capitals)
clojure.lang.PersistentArrayMap
user=> capitals
{:ca "sacramento", :hi "honolulu", :ak "juneau"}
user=> (capitals :ca)
"sacramento"
user=> (count capitals)
3
user=> (keys capitals)
(:ca :hi :ak)
user=> (type (keys capitals))
clojure.lang.APersistentMap$KeySeq

The assoc function returns a new map just like the original one except with one of the fields updated.

user=> (def dueDate {:month 12 :day 16 :year 2015})
#'user/dueDate
user=> dueDate
{:month 12, :day 16, :year 2015}
user=> (assoc dueDate :day 26)
{:month 12, :day 26, :year 2015}
user=> dueDate
{:month 12, :day 16, :year 2015}
user=> (def lateDate (assoc dueDate :day 26))
#'user/lateDate
Exercise: Learn how to create maps with hash-map, array-map, and sorted-map, and research the difference between these three kinds of maps.

Defining Functions

Function objects are introduced with fn:

user=> ((fn [x] (+ x x x)) 20)
60

Like any other value, you can bind a function to a name. This lets you call it through the name:

user=> (def triple (fn [x] (+ x x x)))
#'user/triple
user=> (triple 2)
6

As a convenience you can use defn:

user=> (defn triple [x] (+ x x x))
#'user/triple
user=> (triple 5)
15

There's even a shorter form, #(...) where parameters are called %1, %2, %3 and so one. (You can even use % for %1.)

user=> (def triple #(+ % % %))
#'user/triple
user=> (triple 4)
12

The short form is very convenient for higher-order functions:

user=> (map #(* 3 %) '(1 2 3 4 5 6))
(3 6 9 12 15 18)
user=> (reduce #(+ (* 2 %1) %2) '(1 2 3 4 5 6))
120

Local Variables

user=> (defn energy [m] (let [c 299792458] (* m c c)))
#'user/energy
user=> (energy 75)
6740663840526132300
user=> (defn bmi [pounds inches]
  (let
    [KILOGRAMS_PER_POUND 0.45359237
     METERS_PER_INCH 0.0254
     kilos (* pounds KILOGRAMS_PER_POUND)
     meters (* inches METERS_PER_INCH)
    ]
    (/ kilos (* meters meters))))
#'user/bmi
user=> (bmi 155 69)
22.88926377737234

Local Functions

user=> (letfn [
  #_=>   (sum [x y] (+ x y))
  #_=>   (half [x] (/ x 2))
  #_=> ]
  #_=> (half (sum 100 200)))
150

Structs

Structs are still around, but you should be using records instead.

user=> (defstruct point :x :y)
#'user/point
user=> (struct point 5 8)
{:x 5, :y 8}
user=> (defn makePoint
  ([] (struct point 0 0))
  ([x y] (struct point x y)))
#'user/makePoint
user=> (def p (makePoint 6 8))
#'user/p
user=> (p :x)
6
user=> (:x p)
6

Technical Features

Persistent Data Structures

Clojure strives to make functional programming easier. One of the big things in functional programming is immutability. So Clojure’s data structures (at least almost all of them) are persistent. You don’t mutate them in place. Instead, you create a new data structure that is a modified version of the old one. This is done in a way that is efficient and doesn’t require copying the entire data structure.

Because the data structures are immutable, adding the string "cat" to a list of 50 dogs just tacks a node on the front:

(let [a (repeat 5 "dog") b (conj a "cat")] (list a b))

catdogdog.png

Protocols and Datatypes

A great introduction: Solving the Expression Problem

From the Clojure docs:

Iteration and Recursion

As a functional programming language, Clojure wants you to avoid mutable state as much as possible. How do you do this for simple loops, such as computing a factorial? We would like to use recursion, but we all know the classic recursive algorithm is not good:

; This isn't good!
(defn fact [n] (if (<= n 1) 1 (* (fact (- n 1)) n)))

It is bad because each recursive calls fills up the call stack with unevaluated forms:

fact 4
= 4 * fact 3
= 4 * (3 * fact 2)
= 4 * (3 * (2 * fact 1))
= 4 * (3 * (2 * (1 * fact 0)))
= 4 * (3 * (2 * (1 * 1)))
= 4 * (3 * (2 * 1))
= 4 * 3 * 2
= 4 * 6
= 24

It would be better to create a tail-recursive formulation. Let's make a little function called f that takes in two arguments, and use it as a helper. Like this:

; This is tail recursive so you would think it's good....
(defn fact [n]
  (letfn
    [
      (f [i a] (if (<= i 1) a (f (dec i) (* i a))))
    ]
  (f n 1)))

How does this work? We would like to use recursion, but we all know the = f 8 1 = f 7 8 = f 6 56 = f 5 336 = f 4 1680 = f 3 6720 = f 2 20160 = f 1 40320 = f 40320

That is a neat little function! Notice that we are not mutating the variable i; we're making recursive calls. The binding of the argument to the parameter gives it the feel of updating i and a, but we're not really. FYI, the second variable a stands for "accumulator" because it is building up (accumulating) the result.

This function is tail recursive because it returns the result of a recursive call. So a good compiler and a good runtime system can evaluate this function as if it were a loop! Alas, the JVM cannot do this. So Clojure has loop and recur, to play the role of the inner function. You need to do it this way:

(defn fact [n]
  (loop [i n a 1]
    (if (<= i 1) a (recur (dec i) (* i a)))))

Here the inner recursive helper is replaced with a loop expression that initializes i to n and a to 1, then appears to "call itself," but it's really just repeating the "loop body" with updated values.

Keep in mind, however, that Clojure has lazy sequences and a wealth of powerful sequence operators. So you might actually do factorial this way:

defn factorial [n]
  (reduce * (range 1 (inc n)))

or even:

(defn factorial [n]
  (apply * (range 1 (inc n))))

Sequences

From the documentation:

A seq is a logical list. ... Seqs differ from iterators in that they are persistent and immutable, not stateful cursors into a collection. As such, they are useful for much more than foreach - functions can consume and produce seqs, they are thread safe, they can share structure etc. ...

Most of the sequence library functions are lazy, i.e. functions that return seqs do so incrementally, as they are consumed.

Many of the functions in the seq library take one or more collections, call seq on them, and then operate on the resulting seq. In other words, many of these functions take collections but operate on their seqs.

Please see the the Clojure documentation page on sequences.

Transients

Looping through persistent data structures might generate a bit too much copying. In the middle of your operation, you might want do some mutation, but just in your little temporary world. Transients can speed up certain operations a lot. Read about them.

Here’s another example. Without transients:

(defn change [amount]
  (loop [values [25 10 5 1] remaining amount result []]
    (if (empty? values)
      result
      (recur (rest values) (rem remaining (first values))
        (conj result (quot remaining (first values)))))))

Now with transients:

(defn change [amount]
  (loop [values [25 10 5 1] remaining amount result (transient [])]
    (if (empty? values)
      (persistent! result)
      (recur (rest values) (rem remaining (first values))
        (conj! result (quot remaining (first values)))))))
Exercise: Do a timing study for this little example.

Macros

Ah, macros.... Macros are what makes a Lisp Lisp. They are so cool we need to have a whole page describing them.

Basically a macro looks like a function but the arguments are not evaluated when the macro is called; they are passed to the macro as unevaluated forms. Then the macro may or may not evaluate them.

Here’s the reference.

But you will want to go deeper, so see the Macros chapter in Clojure for the Brave and True book. There’s also a special Learn X in Y Minutes page specifically for Clojure macros.

Interoperating with Java

See the Java interop page at clojure.org for details.

Working with Clojure

The ecosystem is a big part of any major language. Here’s some of Clojure’s.

Unit Tests

physics.clj
(ns physics)

(defn energy [m]
  (let [c 299792458] (* m c c)))
physicstest.clj
(use 'physics)
(use 'clojure.test)

(deftest energy-test
  (is (= (energy 0) 0))
  (is (= (energy 1) 89875517873681764))
  (is (= (energy (/ 1 4)) 22468879468420441)))

(run-tests)

Make sure to put the current directory (or whatever directory the source code is in) on your classpath.

$ java -cp clojure.jar:. clojure.main physicstest.clj

Or better, test with Leiningen.

Building Projects

Use Leiningen to set up, build, and deploy Clojure projects in much the same way you use Maven to manage your Java projects.

Documenting

When defining functions, you can place a doc-string between the function name and the parameter vector, then refer to it later with doc, or use a documentation generator.

user=> (defn square "squares a number" [n] (* n n))
#'user/square
user=> (square 8)
64
user=> (doc square)
-------------------------
user/square
([n])
  squares a number
nil

Libraries

The libraries that are included with Clojure include:

clojure.core, clojure.core.async, clojure.core.protocols, clojure.core.reducers, clojure.data, clojure.data.csv, clojure.inspector, clojure.instant, clojure.java.browse, clojure.java.browse-ui, clojure.java.io, clojure.java.javadoc, clojure.java.shell, clojure.main, clojure.math, clojure.pprint, clojure.reflect, clojure.repl, clojure.set, clojure.stacktrace, clojure.string, clojure.template, clojure.test, clojure.test.junit, clojure.test.tap, clojure.walk, clojure.xml, clojure.zip.

These libraries are actually namespaces. Detailed information on these built-in libraries (namespaces) is at ClojureDocs. Also check out the “Other Included Libraries” documentation at clojure.org.

There are many contributed libraries whose names begin with clojure.contrib. Find information on the contributed libraries ClojureDocs's contrib page.

And More

Here’s the Awesome List.