Reading Clojure Code
Prerequisites: Your first program
Clojure's syntax fits on one page. Once you can read it, everything else is just learning functions.
Prefix notation
In most languages you write 1 + 2 * 3. In Clojure, the operator comes
first, inside parentheses:
(println (+ 1 (* 2 3)))
(println (+ 1 2 3 4 5))
(println (< 1 2 3))
(println (max 4 9 2))
7
15
true
9
- A form
(f a b c)callsfwith the argumentsa,b,c. - Operators like
+and<are ordinary functions, so they take any number of arguments:(< 1 2 3)checks that the numbers increase. - There's no operator precedence to remember — the nesting says it all.
The building blocks
(println 42 3.14 "text" \c true nil) ; numbers, string, character, boolean, nil
(println :keyword 'symbol) ; a keyword and a quoted symbol
(println [1 2 3]) ; vector
(println '(1 2 3)) ; list (quoted, so it isn't called)
(println {:name "Ada" :age 36}) ; map
(println #{:red :green}) ; set
42 3.14 text c true nil
:keyword symbol
[1 2 3]
(1 2 3)
{:name Ada, :age 36}
#{:green :red}
Code is made of the same data structures: a program is lists of
symbols, numbers, strings, vectors, and maps. That's what "code is
data" (homoiconicity) means. Commas are treated as whitespace, so
{:a 1, :b 2} and {:a 1 :b 2} are the same.
Evaluation rules
- Numbers, strings, keywords,
true,false, andnilevaluate to themselves. - A symbol such as
printlnorxevaluates to the value it names. - A list is a call: evaluate the first item (a function), evaluate the arguments, then call.
- A few special forms (
def,if,let,fn,do,quote, ...) and macros have their own rules — for example,ifevaluates only one branch. 'x(quote) stops evaluation:'(1 2 3)is a list of data, not a call to1.
When things go wrong
Clojure reads and evaluates a file one top-level form at a time, so forms before an error still run:
;; illustrative — shows an error
(println "start")
(println (/ 10 0))
(println "never reached")
start
Execution error (ArithmeticException) at user/eval3 (main.clj:3).
Divide by zero
;; illustrative — shows an error
(println "start")
(println (undefined-fn 1))
start
Syntax error compiling at (main.clj:3:10).
Unable to resolve symbol: undefined-fn in this context
The message names the kind of error, the file, and the line (and
column). Clojure then prints Full report at: and the path of a file
with the complete stack trace — trimmed here. A missing closing
parenthesis gives "EOF while reading", pointing at the line where the
unfinished form started.