Clojure:
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
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:
Make a file called hello.clj
that looks like this:
(println "Hello, world")
And run it:
$ clojure -M hello.clj Hello, world
Another simple script:
; 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:
; 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
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?
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
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.
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
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
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"]
Clojure has four basic collection types:
("hello" 1 :c 8 true 9 99999)
["hello" 1 :c 8 true 9 99999]
#{"hello" 1 :c 8 true 9 99999}
{"hello" 1 :c 8 true 9}
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:
count
, conj
, seq
.
empty
, not-empty
, contains?
, distinct?
,
empty?
, every?
, not-every?
, some
,
not-any?
.
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)
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
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]
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
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
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
user=> (letfn [ #_=> (sum [x y] (+ x y)) #_=> (half [x] (/ x 2)) #_=> ] #_=> (half (sum 100 200))) 150
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
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))
A great introduction: Solving the Expression Problem
From the Clojure docs:
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))))
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.
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)))))))
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.
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.
See the Java interop page at clojure.org for details.
The ecosystem is a big part of any major language. Here’s some of Clojure’s.
(ns physics)
(defn energy [m]
(let [c 299792458] (* m c c)))
(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.
Use Leiningen to set up, build, and deploy Clojure projects in much the same way you use Maven to manage your Java projects.
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
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.
Here’s the Awesome List.