Learning Clojure through the REPL

Of course, it's probably easier to read Mark Volkmann's intro (particularly in combination with the comparison list against other Lisps). But it's better to learn by doing.

(The REPL session has been edited, partly to remove uninteresting typos (although the typo rate dropped hugely once I found this tip for readline support under MacPorted Clojure) and partly to make it look like I know more Lisp than I actually do.)

Contents

Getting Started

Last login: Sun Feb 26 08:00:00 on ttys001
~:clj
Clojure 1.3.0
user=> (+ 1 2)
3
user=> ; aha, looks lispy
user=> ; and the familiar semicolon marks a comment
user=> (+ 2 3 4) ; including end-of-line comments?
9
user=> ; yep, including end-of-line comments
user=> ; so how do I set a variable?
user=> (setf x 1)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: setf in this context, compiling:(NO_SOURCE_PATH)
user=> ; nope, not common-lispy.  let's try elispy
user=> (setq x 2)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: setq in this context, compiling:(NO_SOURCE_PATH)
user=> (set x 3)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: x in this context, compiling:(NO_SOURCE_PATH)
user=> ; something scheme-y?
user=> (define x 1)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: define in this context, compiling:(NO_SOURCE_PATH)
user=> (set! x 4)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: x in this context, compiling:(NO_SOURCE_PATH)
user=> ; (look it up)
user=> (def x 5)
#'user/x
user=>
user=> x
5
user=> ; aha
user=> ; but has Clojure fallen for the original sin of Lisps
user=> ; or is it case-sensitive as God intended?
user=> (def X 15)
#'user/X
user=> x
5
user=> X
15
user=> ; yay
user=> ; how about functions?
user=> (defun (x) (+ x x))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: defun in this context, compiling:(NO_SOURCE_PATH)
user=> ; nope, try something else
user=> (def (x) (+ x x))
CompilerException java.lang.RuntimeException: First argument to def must be a Symbol, compiling:(NO_SOURCE_PATH)
user=> ; interesting.
user=> ; wonder what this 'Symbol' means
user=> ; (look up how to specify the argument list)
user=> (defn [x] (+ x x))
IllegalArgumentException Parameter declaration + should be a vector  clojure.core/assert-valid-fdecl (core.clj:6465)
user=> ; can I get help?
user=> (help defn)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: help in this context, compiling:(NO_SOURCE_PATH)
user=> help
CompilerException java.lang.RuntimeException: Unable to resolve symbol: help in this context, compiling:(NO_SOURCE_PATH)
user=> (? defn)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: ? in this context, compiling:(NO_SOURCE_PATH)
user=> ?
CompilerException java.lang.RuntimeException: Unable to resolve symbol: ? in this context, compiling:(NO_SOURCE_PATH)
user=> :?
:?
user=> (doc defn)
-------------------------
clojure.core/defn
([name doc-string? attr-map? [params*] body] [name doc-string? attr-map? ([params*] body) + attr-map?])
Macro
  Same as (def name (fn [params* ] exprs*)) or (def
    name (fn ([params* ] exprs*)+)) with any doc-string or attrs added
    to the var metadata
nil
user=> ; aha!
user=> ; let's try something along these lines
user=> (def f (fn [x] (+ x x)))
#'user/f
user=> ; w00t
user=> (f 2)
4
user=> ; yep, we've got functions
user=> ; but there's clear some sort of macro-driven syntactic sugar we're missing
user=> ; let's try to figure it out
user=> (defn f2 [] ())
#'user/f2
user=> (defn f3 [x] (+ 1 x))
#'user/f3
user=> ; doh
user=> ; I forgot to give it a name the first time round
user=> ; try again
user=> (defn f [x] (+ x x))
#'user/f
user=> (f 2)
4
user=> f
#
user=> x
5
user=> (defn x [x] (+ 3 x))
#'user/x
user=> x
#
user=> (x 2)
5
user=> ; looks like Clojure is a Lisp-1
user=>
user=>
user=>
user=> ; presumably multiple arguments work in an obvious way?
user=> (def my-add2 [x y] (+ x y))
CompilerException java.lang.RuntimeException: Too many arguments to def, compiling:(NO_SOURCE_PATH)
user=> (defn my-add2 [x y] (+ x y))
#'user/my-add2
user=> (my-add 12 23)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: my-add in this context, compiling:(NO_SOURCE_PATH)
user=> (my-add2 12 23)
35
user=> ; yep
user=> ; let's figure out how to get output
user=> ; because that's going to be very useful in our experiments
user=> (format t "hello world")
CompilerException java.lang.RuntimeException: Unable to resolve symbol: t in this context, compiling:(NO_SOURCE_PATH)
user=> ; well it doesn't look to be format
user=> ; but that error message is interesting
user=> ; we might not be in traditional lisp-land
user=> t
CompilerException java.lang.RuntimeException: Unable to resolve symbol: t in this context, compiling:(NO_SOURCE_PATH)
user=> nil
nil
user=> ; well, at least some of the landmarks are familiar
user=> true
true
user=> (not nil)
true
user=> ; aha
user=> ; looks like true is t in clojure
user=> ; back to printing things out
user=> (format true "hello world")
ClassCastException java.lang.Boolean cannot be cast to java.lang.String  clojure.core/format (core.clj:5045)
user=> ; another error message with a hint
user=> (format "hello world")
"hello world"
user=> ; aha       edit: actually, not so much
user=> ; how about parameters?
user=> (format "hello ~a" "world")
"hello ~a"
user=> ; oh well
user=> ; mind you, an observation: strings are double-quote delimited as expected
user=> ; let's try C-style
user=> (format "hello %s" "world")
"hello world"
user=> ; kewl
user=> ;
user=> ; now let's hunt for some control structures
user=> ; iirc, doc looked useful
user=> ; let's try it on a few candidates
user=> (doc if)
-------------------------
if
  (if test then else?)
Special Form
  Evaluates test. If not the singular values nil or false,
  evaluates and yields then, otherwise, evaluates and yields else. If
  else is not supplied it defaults to nil.

  Please see http://clojure.org/special_forms#if
nil
user=> (doc case)
-------------------------
clojure.core/case
([e & clauses])
Macro
  Takes an expression, and a set of clauses.

  Each clause can take the form of either:

  test-constant result-expr

  (test-constant1 ... test-constantN)  result-expr

  The test-constants are not evaluated. They must be compile-time
  literals, and need not be quoted.  If the expression is equal to a
  test-constant, the corresponding result-expr is returned. A single
  default expression can follow the clauses, and its value will be
  returned if no clause matches. If no default expression is provided
  and no clause matches, an IllegalArgumentException is thrown.

  Unlike cond and condp, case does a constant-time dispatch, the
  clauses are not considered sequentially.  All manner of constant
  expressions are acceptable in case, including numbers, strings,
  symbols, keywords, and (Clojure) composites thereof. Note that since
  lists are used to group multiple constants that map to the same
  expression, a vector can be used to match a list if needed. The
  test-constants need not be all of the same type.
nil
user=> (doc while)
-------------------------
clojure.core/while
([test & body])
Macro
  Repeatedly executes body while test expression is true. Presumes
  some side-effect will cause test to become false/nil. Returns nil
nil
user=> (doc let)
-------------------------
clojure.core/let
  (let [bindings*] exprs*)
Special Form
  binding => binding-form init-expr

  Evaluates the exprs in a lexical context in which the symbols in
  the binding-forms are bound to their respective init-exprs or parts
  therein.

  Please see http://clojure.org/special_forms#let
nil
user=> (doc progn)
nil
user=> (doc labels)
nil
user=> ; let's try a few
user=> x
#
user=> (def x 1)
#'user/x
user=> ; hang on a minute
user=> ; before we do any control structures
user=> ; we need to explore equality
user=> ; do we have the panoply of different concepts of equality that common lisp has?
user=> (def y 1)
#'user/y
user=> (def z 1.0)
#'user/z
user=> x
1
user=> y
1
user=>
user=> z
1.0
user=> (equals x x)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: equals in this context, compiling:(NO_SOURCE_PATH)
user=> (equal x x)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: equal in this context, compiling:(NO_SOURCE_PATH)
user=> (eql x x)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: eql in this context, compiling:(NO_SOURCE_PATH)
user=> (= x x)
true
user=> (== x x)
true
user=> (= x y)
true
user=> (= x z)
false
user=> ; OK, there's no automatic conversion between floats and ints
user=> ; good enough for now
user=> ; I think we need to come back to this for a deeper look later
user=> ; when we've found out about atoms and non-atoms etc
user=> x
1
user=> (if (= 1 x) (format "x is one"))
"x is one"
user=> (if (= 2 x) (format "x is two") (format "x isn't two too"))
"x isn't two too"
user=> ; hang on though
user=> (doc if)
-------------------------
if
  (if test then else?)
Special Form
  Evaluates test. If not the singular values nil or false,
  evaluates and yields then, otherwise, evaluates and yields else. If
  else is not supplied it defaults to nil.

  Please see http://clojure.org/special_forms#if
nil
user=> ; presumably we need exactly 2 or 3 arguments to if
user=> (if (= 2 x) (format "x is two") (format "x isn't two") (format "something else")
)
CompilerException java.lang.RuntimeException: Too many arguments to if, compiling:(NO_SOURCE_PATH)
user=> ; ok, just as we thought
user=>
user=>
user=>
user=> ; so we've got enough for a Lisp-style hello world
user=> (defn factorial [n] (if (= n 0) 1 (factorial (- n 1))))
#'user/factorial
user=> (factorial 1)
1
user=> (factorial 2)
1
user=> (factorial 3)
1
user=> ; oops missed a key step
user=>
user=>
user=> (defn factorial [n] (if (= n 0) 1 (factorial (- n 1))))
#'user/factorial
user=> (defn factorial [n] (if (= n 0) 1 (* n (factorial (- n 1)))))
#'user/factorial
user=> (factorial 3)
6
user=> (factorial 4)
24
user=> ; that's more like it
user=> ; and it's recursive, so we feel we're properly in Lisp land
user=>
user=> ; how about some binding creation stuff
user=> (let (c 1) (format "hello"))
IllegalArgumentException let requires a vector for its binding  clojure.core/let (core.clj:3962)
user=> ; it's talking about 'vectors' again
user=> ; that needed square brackets before
user=> (let [c 1] (format "hello"))
"hello"
user=> (let [c 1] (format "hello number ~a" c))
"hello number ~a"
user=> ; drat, forgot the format specifier
user=> (let [c 1] (format "hello number %s" c))
"hello number 1"
user=> ; how about multiple bindings?
user=> (let [c 1 d 2] (format "hello number %s" c))
"hello number 1"
user=> (let [c 1 d 2] (format "this format was brought to you by the numbers %s and %s" c d))
"this format was brought to you by the numbers 1 and 2"
user=> ; how about let* ?
user=> (let [c 1 d (+ c 2)] (format "this format was brought to you by the numbers %s and %s" c d))
"this format was brought to you by the numbers 1 and 3"
user=> (let [c 1 d (+ c 2) c 5] (format "this format was brought to you by the numbers %s and %s" c d))
"this format was brought to you by the numbers 5 and 3"
user=> (let [d (+ c 2) c 5] (format "this format was brought to you by the numbers %s and %s" c d))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: c in this context, compiling:(NO_SOURCE_PATH)
user=> ; so let seems to be like LET*

Basic Data Types

~:clj
Clojure 1.3.0
user=> ; let's have a look at the most basic bricks for data
user=> ; we've already seen a couple of numeric types
user=> 1
1
user=> 1.0
1.0
user=> (= 1 1.0)
false
user=> true
true
user=> (= false true)
false
user=> ; well, that's reassuring
user=> (type 1)
java.lang.Long
user=> ; ooh
user=> ; now that's interesting
user=> ; a) we've got a type thingy
user=> ; b) the base type comes from Java
user=> ;
user=> ; what type is a type?
user=> (doc type)
-------------------------
clojure.core/type
([x])
  Returns the :type metadata of x, or its Class if none
nil
user=> (type (type 1))
java.lang.Class
user=> ; hmm
user=> ; that has a sniff of interesting possibilities
user=> ; ... to come back to
user=>
user=> ;
user=> ; back to b)
user=> ; how many of the Java POD types can we get at?
user=> 'a'
a'
user=> ; ah, oops, been writing too much Python
user=> ; of course single quotes don't enclose things
user=> ; we're in Lisp-land
user=> ; try again
user=> "a"
"a"
user=> (type "a")
java.lang.String
user=> (type 1.0)
java.lang.Double
user=> ; interesting to note that it's calling this
user=> ; the wrapper type 'java.lang.Double' not the primitive type double
user=> float
#
user=> (float 1.0)
1.0
user=> (def x (float 1.0))
#'user/x
user=> c
CompilerException java.lang.RuntimeException: Unable to resolve symbol: c in this context, compiling:(NO_SOURCE_PATH)
user=> x
1.0
user=> (type x)
java.lang.Float
user=> ; so it's defaulting to Double but you can have less precision if you want
user=> ; how about integral types?
user=> (int 1)
1
user=> (type (int 1))
java.lang.Long
user=> (type (short 1))
java.lang.Short
user=> (type false)
java.lang.Boolean
user=> (type (byte 1))
java.lang.Byte
user=> ; that mostly makes sense
user=> ; not sure why int is missing
user=> ; let's check the range
user=> (def bb (byte 255))
IllegalArgumentException Value out of range for byte: 255  clojure.lang.RT.byteCast (RT.java:997)
user=> ; aha, -128 to 127 like Java I'm guessing
user=> ; (although why on earth the Java developers thought that was a good idea for a byte type is beyond me)user=> (def bb (byte 127))
#'user/bb
user=> (def bb (byte 128))
IllegalArgumentException Value out of range for byte: 128  clojure.lang.RT.byteCast (RT.java:997)
user=> bb
127
user=> (+ bb 1)
128
user=> (type (+ bb 1))
java.lang.Long
user=> ; OK, looks like either promotion on mixed types
user=> ; or promotion on overflow
user=> ; let's figure out which
user=> (type (+ (byte 1) (byte 2)))
java.lang.Long
user=> (def x (byte 1))
#'user/x
user=> (def y (byte 2))
#'user/y
user=> (type x y)
ArityException Wrong number of args (2) passed to: core$type  clojure.lang.AFn.throwArity (AFn.java:437)
user=> (mapcar type '(x y))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: mapcar in this context, compiling:(NO_SOURCE_PATH)
user=> ; OK, maybe we'll come back to that
user=> (type x)
java.lang.Byte
user=> (type y)
java.lang.Byte
user=> (+ x y)
3
user=> (def z (+ x y))
#'user/z
user=> (type z)
java.lang.Long
user=> ; for bytes, looks like promotion on arithmetic operation
user=> (def x (short 1))
#'user/x
user=> (def y (short 2))
#'user/y
user=> (def z (+ x y))
#'user/z
user=> (type z)
java.lang.Long
user=> ; same for shorts
user=> ; would be a bit disappointing at the beach though
user=>
user=>
user=> ; if your pair of shorts got automatically converted to longs
user=>
user=>
user=> ; moving swiftly on
user=> (char 'a')
ClassCastException clojure.lang.Symbol cannot be cast to java.lang.Number  clojure.lang.RT.charCast (RT.java:905)
user=> (char 32)
\space
user=> (type (char 32))
java.lang.Character
user=> ; given we've got a Java substratum, I'm guessing that...
user=> (def a_macron (char 256))
#'user/a_macron
user=> (type a_macron)
java.lang.Character
user=> a_macron
\?
user=> (format a_macron)
ClassCastException java.lang.Character cannot be cast to java.lang.String  clojure.core/format (core.clj:5045)
user=> (format "%s" a_macron)
"?"
user=> ; hmm, dunno if that's just a missing font/encoding
user=> ord
CompilerException java.lang.RuntimeException: Unable to resolve symbol: ord in this context, compiling:(NO_SOURCE_PATH)
user=> (doc (type a_macron))
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol  clojure.core/ns-resolve (core.clj:3879)
user=> (doc java.lang.Character)
CompilerException java.lang.RuntimeException: Unable to resolve var: java.lang.Character in this context, compiling:(NO_SOURCE_PATH)
user=> ; digression {
user=> ; can we specify numbers in other bases?
user=> 0x1
1
user=> 0xF
15
user=> ; kewl
user=> ; makes it easier to...
user=> ; } undigress
user=> ; get outside the BMP
user=> (char 0x10100)
IllegalArgumentException Value out of range for char: 65792  clojure.lang.RT.charCast (RT.java:940)
user=> ; or not
user=> ; (that should have been AEGEAN WORD SEPARATOR LINE)
user=> ; (for anyone who cares)
user=>
user=> ; strings look to be fairly built-in
user=> (def hw "hello world")
#'user/hw
user=> hw
"hello world"
user=> (type hw)
java.lang.String
user=> ; but do they count as a compound type of some form?
user=> (first hw)
\h
user=> (type (first hw))
java.lang.Character
user=> ; so a string can be broken down into characters
user=> (string "abc")
CompilerException java.lang.RuntimeException: Unable to resolve symbol: string in this context, compiling:(NO_SOURCE_PATH)
user=> (doc string)
nil
user=> (str (char 32) (char 34))
" \""
user=> (type (str (char 32) (char 34)))
java.lang.String
user=> ; and we can build characters back up into strings
user=>

Collections

user=> ; of course, this wouldn't be Lisp
user=> ; without lists
user=> (list 1 2 3)
(1 2 3)
user=> ; how about the normal syntactic sugar?
user=> '(1 2 3)
(1 2 3)
user=> (def x (list 1 2 3))
#'user/x
user=> (type x)
clojure.lang.PersistentList
user=> ; hmm
user=> ; I wonder if there's a non-Persistent list?
user=> ;
user=> ; let's try to be a bit trad
user=> (cons 1 2)
IllegalArgumentException Don't know how to create ISeq from: java.lang.Long  clojure.lang.RT.seqFrom (RT.java:487)
user=> x
(1 2 3)
user=> (car x)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: car in this context, compiling:(NO_SOURCE_PATH)
user=> ; these young whippersnappers
user=> ; no respect for tradition
user=> (cdr x)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: cdr in this context, compiling:(NO_SOURCE_PATH)
user=> (first x)
1
user=> (rest x)
(2 3)
user=> (1 . 2)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: . in this context, compiling:(NO_SOURCE_PATH)
user=> ; interesting
user=> ; no cons cells
user=> ; there must be some other way of doing the key data structures
user=> ; that traditionally use cons cells directly
user=>
user=> ; now, we've seen some other sequence types
user=> (setq ss "abcde")
CompilerException java.lang.RuntimeException: Unable to resolve symbol: setq in this context, compiling:(NO_SOURCE_PATH)
user=> ; drat, forgot again
user=> (def ss "abcde")
#'user/ss
user=> ; lets set up a little utility function
user=> (defn printall [x] (if x (do (format "%s" (first x)) (printall (rest x)))))
#'user/printall
user=> ; (I cheated a bit, and looked up that PROGN is 'do' in Clojure)
user=> (printall ss)
StackOverflowError   java.util.regex.Pattern$CharProperty.match (Pattern.java:3343)
user=> (def y '())
#'user/y
user=> (if y (format "empty list evaluates to true") (format "empty list is falsy"))
"empty list evaluates to true"
user=> (listp y)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: listp in this context, compiling:(NO_SOURCE_PATH)
user=> (list? y)
true
user=> ; aha, Scheme-style. Nice
user=> (nil? y)
false
user=> (empty? y)
true
user=> (empty? x)
false
user=> ; let's try again
user=> (defn printall [x] (if (empty? x) () (do (format "%s" (first x)) (printall (rest x)))))
#'user/printall
user=> (printall x)
()
user=> (printall ss)
()
user=> (not true)
false
user=> ; Ok, that lets us make it neater...
user=> (defn printall [x] (if (not (empty? x)) (do (format "%s" (first x)) (printall (rest x)))))
#'user/printall
user=> (printall ss)
nil
user=> ; ...but no more functional :-(
user=> (defn temp [] (format "dasdf"))
#'user/temp
user=> (temp)
"dasdf"
user=> (def xyzzy (temp))
#'user/xyzzy
user=> ; OK, so output doesn't appear
user=> ; looks like I misunderstood format
user=> ; it's not an output function like Common Lisp
user=> ; let's try something more Java-esque
user=> (print "hello")
hellonil
user=> (println "hello")
hello
nil
user=> ; aha
user=> (defn printall [x] (if (not (empty? x)) (do (println (first x)) (printall (rest x)))))
#'user/printall
user=> (printall ss)
a
b
c
d
e
nil
user=> ; phew
user=> (printall x)
1
2
3
nil
user=> ; how about those square brackets in argument lists
user=> ; there was muttering about 'vectors'
user=> (def vv [1 2 3])
#'user/vv
user=> (type vv)
clojure.lang.PersistentVector
user=> (printall vv)
1
2
3
nil
user=> ; so first and rest work on vectors OK
user=> (doc time)
-------------------------
clojure.core/time
([expr])
Macro
  Evaluates expr and prints the time it took.  Returns the value of
 expr.
nil
user=> (doc vec)
-------------------------
clojure.core/vec
([coll])
  Creates a new vector containing the contents of coll.
nil
user=> (vec (range 10))
[0 1 2 3 4 5 6 7 8 9]
user=> (list (range 10))
((0 1 2 3 4 5 6 7 8 9))
user=> (flatten (list (range 10)))
(0 1 2 3 4 5 6 7 8 9)
user=> ; OK, we can build some lists and vectors
user=> ; big 'uns
user=> (def longv (vec (range 10000)))
#'user/longv
user=> (def longl (flatten (list (range 10000))))
#'user/longl
user=> (nth x 10)
10
user=> (nth longv 9999)
9999
user=> (nth longl 9999)
9999
user=> (time (nth longl 9999))
"Elapsed time: 0.834 msecs"
9999
user=> (time (nth longv 9999))
"Elapsed time: 0.034 msecs"
9999
user=> ; as expected, random list access is probably O(N)
user=> ; whereas vector is more O(1)-ish
user=>
user=> ; OK, so far we've got a list
user=> (list 1 2 3)
(1 2 3)
user=> ; with the usual syntactic sugar
user=> '(4 5 6)
(4 5 6)
user=> (type '(4 5 6))
clojure.lang.PersistentList
user=> (type (list 4 5 6))
clojure.lang.PersistentList
user=> ; and a vector
user=> (type (vector 1 2 3))
clojure.lang.PersistentVector
user=> ; with a new grain of syntactic sugar, namely square brackets
user=> (type [4 5 6])
clojure.lang.PersistentVector
user=> ; We've also found that lists aren't built from conses
user=> (1 . 2)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: . in this context, compiling:(NO_SOURCE_PATH)
user=>
user=> ; so what else is there?
user=> ; a quick sneaky peek at the docs
user=> ; talks about maps and sets as other collection types
user=> ; so let's explore
user=>
user=> (doc map)
-------------------------
clojure.core/map
([f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls])
  Returns a lazy sequence consisting of the result of applying f to the
  set of first items of each coll, followed by applying f to the set
  of second items in each coll, until any one of the colls is
  exhausted.  Any remaining items in other colls are ignored. Function
  f should accept number-of-colls arguments.
nil
user=> ; OK, that's a mapcar-type thingy
user=> (doc map?)
-------------------------
clojure.core/map?
([x])
  Return true if x implements IPersistentMap
nil
user=> ; cheat and look up the fact there are two sorts of map
user=> (doc hash-map)
-------------------------
clojure.core/hash-map
([] [& keyvals])
  keyval => key val
  Returns a new hash map with supplied mappings.
nil
user=> (doc sorted-map)
-------------------------
clojure.core/sorted-map
([& keyvals])
  keyval => key val
  Returns a new sorted map with supplied mappings.
nil
user=> (hash-map :a 1 :b 2)
{:a 1, :b 2}
user=> (def hm (hash-map :a 1 :b 2))
#'user/hm
user=> (type hm)
clojure.lang.PersistentHashMap
user=> (hm :a)
1
user=> (hm :b)
2
user=> (hm :c)
nil
user=> ; so looking up a value is straightforward: the map object acts like a lookup function
user=> ; how about testing?
user=> (:c in hm)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: in in this context, compiling:(NO_SOURCE_PATH)
user=> (in :c hm)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: in in this context, compiling:(NO_SOURCE_PATH)
user=> (in? :c hm)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: in? in this context, compiling:(NO_SOURCE_PATH)
user=> (doc hm)
-------------------------
user/hm
  nil
nil
user=> (doc hash-map)
-------------------------
clojure.core/hash-map
([] [& keyvals])
  keyval => key val
  Returns a new hash map with supplied mappings.
nil
user=> (values hm)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: values in this context, compiling:(NO_SOURCE_PATH)
user=> (vals hm)
(1 2)
user=> ; aha
user=> ; that leads to a logical guess:
user=> (keys hm)
(:a :b)
user=> (type (keys hm))
clojure.lang.APersistentMap$KeySeq
user=> (count hm)
2
user=> (len hm)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: len in this context, compiling:(NO_SOURCE_PATH)
user=> hm
{:a 1, :b 2}
user=> (id hm)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: id in this context, compiling:(NO_SOURCE_PATH)
user=> (first hm)
[:a 1]
user=> (nth hm 3)
UnsupportedOperationException nth not supported on this type: PersistentHashMap  clojure.lang.RT.nthFrom (RT.java:776)
user=> ; how about modifying the map?
user=> ; the sneak peak earlier mentioned 'assoc' and 'dissoc'
user=> ; so let's have a go
user=> ;
user=> ; but before we start, let's save off our original hash-map
user=> (def ohm hm)
#'user/ohm
user=> ohm
{:a 1, :b 2}
user=> (doc assoc)
-------------------------
clojure.core/assoc
([map key val] [map key val & kvs])
  assoc[iate]. When applied to a map, returns a new map of the
    same (hashed/sorted) type, that contains the mapping of key(s) to
    val(s). When applied to a vector, returns a new vector that
    contains val at index. Note - index must be <= (count vector).
nil
user=> (assoc hm :d 4)
{:a 1, :b 2, :d 4}
user=> hm
{:a 1, :b 2}
user=> ; interesting
user=> ; the original hash-map is unchanged, but the assoc operation returns a new one
user=> (def newhm (assoc hm :d 4))
#'user/newhm
user=> newhm
{:a 1, :b 2, :d 4}
user=> hm
{:a 1, :b 2}
user=> ohm
{:a 1, :b 2}
user=> (== ohm hm)
ClassCastException clojure.lang.PersistentHashMap cannot be cast to java.lang.Number  clojure.lang.Numbers.equiv (Numbers.java:206)
user=> ; interesting digression -- looks like == is just for numbers
user=> (= ohm hm)
true
user=> (= ohm newhm)
false
user=> (doc dissoc)
-------------------------
clojure.core/dissoc
([map] [map key] [map key & ks])
  dissoc[iate]. Returns a new map of the same (hashed/sorted) type,
  that does not contain a mapping for key(s).
nil
user=> (def newhm (dissoc :a))
#'user/newhm
user=> newhm
:a
user=> (doc set)
-------------------------
clojure.core/set
([coll])
  Returns a set of the distinct elements of coll.
nil
user=> (set 1 2 3 4 3 2 1)
ArityException Wrong number of args (7) passed to: core$set  clojure.lang.AFn.throwArity (AFn.java:437)
user=> (set [1 2 3 4 3 2 1])
#{1 2 3 4}
user=> (def ss (set [1 2 3 4 3 2 1]))
#'user/ss
user=> (keys ss)
ClassCastException java.lang.Long cannot be cast to java.util.Map$Entry  clojure.lang.APersistentMap$KeySeq.first (APersistentMap.java:132)
(user=>
user=> (vals ss)
ClassCastException java.lang.Long cannot be cast to java.util.Map$Entry  clojure.lang.APersistentMap$ValSeq.first (APersistentMap.java:163)
(user=> (ss 1)
1
user=> (ss 9)
nil
user=> (ss 2)
2
user=> ; ok, treated as a function, (set x) returns x if it's in the set, nil otherwise
user=> (def ss_with_nil (set '(1 2 nil 4)))
#'user/ss_with_nil
user=> ss_with_nil
#{nil 1 2 4}
user=> (ss nil)
nil
user=> ; hmm, there must be some other way to test membership
user=> (len ss)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: len in this context, compiling:(NO_SOURCE_PATH)
user=> (count ss)
4
user=> (contains? ss nil)
false
user=> (contains? ss_with_nil nil)
true
user=> ; aha
user=> (assoc ss 8)
ArityException Wrong number of args (2) passed to: core$assoc  clojure.lang.AFn.throwArity (AFn.java:437)
user=> ss
#{1 2 3 4}
user=> ; looks like add/remove are conj/disj
user=> (conj ss 7)
#{1 2 3 4 7}
user=> (disj ss 2)
#{1 3 4}
user=> ; but again these return a new set
user=> (def ss_with_7 (conj ss 7))
#'user/ss_with_7
user=> (= ss ss_with_7)
false
user=> ss
#{1 2 3 4}
user=> ss_with_7
#{1 2 3 4 7}
user=> ;
user=> ;
user=> ; pour some sugar on me
user=> ; with both hash-maps and sets it looks like there might be some syntactic sugar
user=> (type ss)
clojure.lang.PersistentHashSet
user=> ss
#{1 2 3 4}
user=> (def ss2 #{2 4 6 8})
#'user/ss2
user=> ss2
#{2 4 6 8}
user=> (type ss2)
clojure.lang.PersistentHashSet
user=> (type hm)
clojure.lang.PersistentHashMap
user=> hm
{:a 1, :b 2}
user=> (def hm2 {:b 2 :d 4 :f 6})
#'user/hm2
user=> (type hm2)
clojure.lang.PersistentHashMap
user=> hm2
{:b 2, :f 6, :d 4}
user=>
user=> ; how about iteration over all of these different sequence types?
user=> (doc for)
-------------------------
clojure.core/for
([seq-exprs body-expr])
Macro
  List comprehension. Takes a vector of one or more
   binding-form/collection-expr pairs, each followed by zero or more
   modifiers, and yields a lazy sequence of evaluations of expr.
   Collections are iterated in a nested fashion, rightmost fastest,
   and nested coll-exprs can refer to bindings created in prior
   binding-forms.  Supported modifiers are: :let [binding-form expr ...],
   :while test, :when test.

  (take 100 (for [x (range 100000000) y (range 1000000) :while (< y x)] [x y]))
nil
user=> (doc foreach)
nil
user=> (doc doseq)
-------------------------
clojure.core/doseq
([seq-exprs & body])
Macro
  Repeatedly executes body (presumably for side-effects) with
  bindings and filtering as provided by "for".  Does not retain
  the head of the sequence. Returns nil.
nil
user=> ; aha
user=> (doseq hm)
IllegalArgumentException doseq requires a vector for its binding  clojure.core/doseq (core.clj:2804)
user=> (doseq [hm])
IllegalArgumentException doseq requires an even number of forms in binding vector  clojure.core/doseq (core.clj:2805)
user=> (doseq [x hm])
nil
user=> (doseq [x hm] (println x))
[:a 1]
[:b 2]
nil
user=> (doseq [x ss] (println x))
1
2
3
4
nil
user=> (doseq [x '(1 2 3)] (println x))
1
2
3
nil
user=> (doseq [x [1 2 3]] (println x))
1
2
3
nil

Functions and Lambdas

user=> ; We wouldn't be in Lisp-land
user=> ; without functions being first class beasties
user=> ; so let's explore
user=> ;
user=> ;
user=> ; We already had the basics:
user=> (defun add2 [x] (+ x 2))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: defun in this context, compiling:(NO_SOURCE_PATH)
user=> (defn add2 [x] (+ x 2))
#'user/add2
user=> (type add2)
user$add2
user=> (add2 9)
11
user=> (add2 'a')
ClassCastException clojure.lang.Symbol cannot be cast to java.lang.Number  clojure.lang.Numbers.add (Numbers.java:126)
user=> ; how about lambdas?
user=> (doc lambda)
nil
user=> (lambda x: (+ x 2))
RuntimeException Invalid token: x:  clojure.lang.Util.runtimeException (Util.java:156)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: x in this context, compiling:(NO_SOURCE_PATH)
RuntimeException Unmatched delimiter: )  clojure.lang.Util.runtimeException (Util.java:156)
user=> (lambda [x] (+ x 2))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: lambda in this context, compiling:(NO_SOURCE_PATH)
user=> (lambda (x) (+ x 2))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: lambda in this context, compiling:(NO_SOURCE_PATH)
user=> (fn (x) (+ x 2))
CompilerException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol, compiling:(NO_SOURCE_PATH)
user=> (fn [x] (+ x 2))
#
user=> ; looks like we've stumbled on something
user=> (def add2_lambda (fn [x] (+ x 2)))
#'user/add2_lambda
user=> (type add2_lambda)
user$add2_lambda
user=> (add2_lambda 9)
11
user=> ; OK, how about making lambdas on the fly
user=> (defn make-adder [y] (fn [x] (+ x y)))
#'user/make-adder
user=> ((make-adder 5) 4)
9
user=> ((make-adder 15) 4)
19
user=> (doc defn)
-------------------------
clojure.core/defn
([name doc-string? attr-map? [params*] body] [name doc-string? attr-map? ([params*] body) + attr-map?])
Macro
  Same as (def name (fn [params* ] exprs*)) or (def
    name (fn ([params* ] exprs*)+)) with any doc-string or attrs added
    to the var metadata
nil
user=> (doc fn)
-------------------------
clojure.core/fn
  (fn name? [params*] exprs*)
  (fn name? ([params*] exprs*) +)
Special Form
  params => positional-params* , or positional-params* & next-param
  positional-param => binding-form
  next-param => binding-form
  name => symbol

  Defines a function

  Please see http://clojure.org/special_forms#fn
nil
user=> ; so defn is a convenience macro that expands to doing (def name (fn ....
user=> ; which makes it pretty clear that Clojure is a Lisp-1
user=> ;
user=> ; there's also a hint of how to get varargs arguments
user=> ; (to mix metaphors and pull in a C-ism)
user=> (defn addup [x & r] (map (make-adder x) r))
#'user/addup
user=> (addup 10 1 2 3 4 5)
(11 12 13 14 15)
user=> ; how about &optional arguments?
user=> (defn with-opt [x y &optional z] (list x y z))
#'user/with-opt
user=> (doc with-opt)
-------------------------
user/with-opt
([x y &optional z])
  nil
nil
user=> (with-opt 1 2)
ArityException Wrong number of args (2) passed to: user$with-opt  clojure.lang.AFn.throwArity (AFn.java:437)
user=> (with-opt 1 2 3)
ArityException Wrong number of args (3) passed to: user$with-opt  clojure.lang.AFn.throwArity (AFn.java:437)
user=> ; apparently not
user=> ; or at least, not like that
user=> ; try something like a destructuring-bind
user=> (defn with-opt [x y & [z]] (list x y z))
#'user/with-opt
user=> (with-opt 1 2 3)
(1 2 3)
user=> (with-opt 1 2)
(1 2 nil)
user=>
user=> ; OK, for an encore, how about keyword arguments
user=> (defn kw (&key x y z) (list x y z))
IllegalArgumentException Parameter declaration &key should be a vector  clojure.core/assert-valid-fdecl (core.clj:6465)
user=> ; look this one up.  An article converting Practial Common Lisp to Clojure is particularly useful
user=> (defn kw [{:keys x y z}] (list x y z))
CompilerException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol, compiling:(NO_SOURCE_PATH)
user=> (defn kw [{:keys [x y z]}] (list x y z))
#'user/kw
user=> (kw :x 1 :y 2)
ArityException Wrong number of args (4) passed to: user$kw  clojure.lang.AFn.throwArity (AFn.java:437)
user=> (kw :x 1 :y 2 :z 3)
ArityException Wrong number of args (6) passed to: user$kw  clojure.lang.AFn.throwArity (AFn.java:437)
user=> (kw {:x 1 :y 2})
(1 2 nil)
user=> (kw {:x 1 :y 2 :z 3})
(1 2 3)
user=> ; so it's more like a function that takes a single argument
user=> ; with a destructuring-bind to enforce a map structure on that single arg
user=> ; one more thing, spotted a while back
user=> (doc fn)
-------------------------
clojure.core/fn
  (fn name? [params*] exprs*)
  (fn name? ([params*] exprs*) +)
Special Form
  params => positional-params* , or positional-params* & next-param
  positional-param => binding-form
  next-param => binding-form
  name => symbol

  Defines a function

  Please see http://clojure.org/special_forms#fn
nil
user=> ; hmm, what's that plus doing at the end of the second form?
user=> (defn add-some [x y] (+ x y) [x y z] (+ x y z))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: z in this context, compiling:(NO_SOURCE_PATH)
user=> ; ah, forgot some Inconsequential Parentheses
user=> (defn add-some ([x y] (+ x y)) ([x y z] (+ x y z)))
#'user/add-some
user=> (add-some 1 2)
3
user=> (add-some 3 4 5)
12
user=> ; so we have overloading on number of arguments too
user=> ; What about clojures?
user=> ; I mean
user=> ; What about closures?
user=> (def add11 (make-adder 11))
#'user/add11
user=> (add11 9)
20
user=> ; as expected

Structures and Objects

user=> ; what about structures and classes and records and objects
user=> ; and so on
user=> ; we've seen a hash-map for less formally-structured collections of data
user=> ; is there anything more rigorously organized?
user=> (doc defclass)
nil
user=> (doc defstruct)
-------------------------
clojure.core/defstruct
([name & keys])
Macro
  Same as (def name (create-struct keys...))
nil
user=> (doc create-struct)
-------------------------
clojure.core/create-struct
([& keys])
  Returns a structure basis object.
nil
user=> (defstruct point :x :y)
#'user/point
user=> (doc point)
-------------------------
user/point
  nil
nil
user=> (point :x 1 :y 2)
ClassCastException clojure.lang.PersistentStructMap$Def cannot be cast to clojure.lang.IFn  user/eval7 (NO_SOURCE_FILE:6)
user=> (point [:x 1 :y 2])
ClassCastException clojure.lang.PersistentStructMap$Def cannot be cast to clojure.lang.IFn  user/eval9 (NO_SOURCE_FILE:7)
user=> (point {:x 1 :y 2})
ClassCastException clojure.lang.PersistentStructMap$Def cannot be cast to clojure.lang.IFn  user/eval11 (NO_SOURCE_FILE:8)
user=> (create-struct :x 1 :y 2)
#
user=> (point 1 2)
ClassCastException clojure.lang.PersistentStructMap$Def cannot be cast to clojure.lang.IFn  user/eval15
(NO_SOURCE_FILE:10)
user=> (doc struct)
-------------------------
clojure.core/struct
([s & vals])
  Returns a new structmap instance with the keys of the
  structure-basis. vals must be supplied for basis keys in order -
  where values are not supplied they will default to nil.
nil
user=> (struct point 1 2)
{:x 1, :y 2}
user=> (type point)
clojure.lang.PersistentStructMap$Def
user=> ; so a struct is just a map
user=> ; and we've just made a shortcut function for building a map
user=> ; with 2 known parameters in a known order (x then y)
user=> (def pp (struct point 1 2))
CompilerException java.lang.IllegalStateException: pp already refers to: #'clojure.pprint/pp in namespace: user, compiling:(NO_SOURCE_PATH)
user=> (def apoint (struct point 1 2))
#'user/apoint
user=> (apoint :x)
1
user=> (apoint :y)
2
user=> (type apoint)
clojure.lang.PersistentStructMap
user=> (dissoc apoint :x)
RuntimeException Can't remove struct key  clojure.lang.Util.runtimeException (Util.java:156)
user=> (assoc apoint :z 3)
{:x 1, :y 2, :z 3}
user=> ; so there is the odd restriction
user=>
user=> (doc defrecord)
-------------------------
clojure.core/defrecord
([name [& fields] & opts+specs])
Macro
  Alpha - subject to change

  (defrecord name [fields*]  options* specs*)

  Currently there are no options.

  Each spec consists of a protocol or interface name followed by zero
  or more method bodies:

  protocol-or-interface-or-Object
  (methodName [args*] body)*

  Dynamically generates compiled bytecode for class with the given
  name, in a package with the same name as the current namespace, the
  given fields, and, optionally, methods for protocols and/or
  interfaces.

  The class will have the (immutable) fields named by
  fields, which can have type hints. Protocols/interfaces and methods
  are optional. The only methods that can be supplied are those
  declared in the protocols/interfaces.  Note that method bodies are
  not closures, the local environment includes only the named fields,
  and those fields can be accessed directy.

  Method definitions take the form:

  (methodname [args*] body)

  The argument and return types can be hinted on the arg and
  methodname symbols. If not supplied, they will be inferred, so type
  hints should be reserved for disambiguation.

  Methods should be supplied for all methods of the desired
  protocol(s) and interface(s). You can also define overrides for
  methods of Object. Note that a parameter must be supplied to
  correspond to the target object ('this' in Java parlance). Thus
  methods for interfaces will take one more argument than do the
  interface declarations. Note also that recur calls to the method
  head should *not* pass the target object, it will be supplied
  automatically and can not be substituted.

  In the method bodies, the (unqualified) name can be used to name the
  class (for calls to new, instance? etc).

  The class will have implementations of several (clojure.lang)
  interfaces generated automatically: IObj (metadata support) and
  IPersistentMap, and all of their superinterfaces.

  In addition, defrecord will define type-and-value-based =,
  and will defined Java .hashCode and .equals consistent with the
  contract for java.util.Map.

  When AOT compiling, generates compiled bytecode for a class with the
  given name (a symbol), prepends the current ns as the package, and
  writes the .class file to the *compile-path* directory.

  Two constructors will be defined, one taking the designated fields
  followed by a metadata map (nil for none) and an extension field
  map (nil for none), and one taking only the fields (using nil for
  meta and extension fields).
nil
user=> ; whoa
user=> ; there's a lot of stuff there
user=> ; particularly in comparison to the other docstrings
user=> ; doth protest too much, perhaps?
user=> ; can't help but notice the prominent "Alpha - subject to change"
user=> ; so maybe just move on

Control Flow and Exceptions

user=> ; OK, let's look at transfer of control
user=> ; the simplest way to get out of a function is to get to the end
user=> (defn f1 [x] (+ 1 x) 2)
#'user/f1
user=> (f1 10)
2
user=> ; looks like the last thing evaluated is returned
user=> ; in proper functional style
user=> ; any other expressions are being evaluated purely for their side effects
user=> ; (if you're grubby enough to do such a thing)
user=>
user=> (doc prog1)
nil
user=> (doc prog2)
nil
user=> (doc do)
-------------------------
do
  (do exprs*)
Special Form
  Evaluates the expressions in order and returns the value of
  the last. If no expressions are supplied, returns nil.

  Please see http://clojure.org/special_forms#do
nil
user=> (doc do1)
nil
user=> ; no obvious way to evaluate multiple things and return the first of them
user=> ; although it's easy to simulate with a temp
user=> (defn f2 [x]
         (let [result (+ 1 x)]
            2
            result))
#'user/f2
user=> (f2 10)
11
user=> ; how about early bath conditions?
user=> (def to-ten '(1 2 3 4 5 6 7 8 9 10))
#'user/to-ten
user=> (% 10 2)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: % in this context, compiling:(NO_SOURCE_PATH)
user=> (mod 10 2)
0
user=> (doc mod)
-------------------------
clojure.core/mod
([num div])
  Modulus of num and div. Truncates toward negative infinity.
nil
user=> (mod 3 3)
0
user=> (mod 4 3)
1
user=> (defn find-multiple [x s]
          (doseq [val s]
             (if (== (mod val x) 0) (return val))))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: return in this context, compiling:(NO_SOURCE_PATH)
user=> (doc return-from)
nil
user=> (doc return)
nil
user=> (doc ret)
nil
user=> (doc yield)
nil
user=> ; look it up on the Internet
user=> ; which basically means Stack Overflow these days, for programming questions
user=> ; so no dice
user=>
user=>
user=> ; how about exceptions
user=> (doc raise)
nil
user=> (doc throw)
-------------------------
throw
  (throw expr)
Special Form
  The expr is evaluated and thrown, therefore it should
  yield an instance of some derivee of Throwable.

  Please see http://clojure.org/special_forms#throw
nil
user=> (doc Throwable)
CompilerException java.lang.RuntimeException: Expecting var, but Throwable is mapped to class java.lang.Throwable, compiling:(NO_SOURCE_PATH)
user=> (Exception "fred")
RuntimeException Expecting var, but Exception is mapped to class java.lang.Exception  clojure.lang.Util.runtimeException (Util.java:156)
user=> (Exception. "fred")
#
user=> ; (there's a cheat here.  We'll come back to the magic dot)
user=> ; (or 'period', for the Americans amongst us)
user=> (throw (Exception. "fred"))
Exception fred  user/eval59 (NO_SOURCE_FILE:94)
user=>
user=> (defn find-multiple [x s]
          (doseq [val s]
             (if (== (mod val x) 0) (throw (Exception. "not really that exceptional")))))
#'user/find-multiple
user=> (find-multiple 3 to-ten)
Exception not really that exceptional  user/find-multiple (NO_SOURCE_FILE:131)
user=>
user=> ; like jugglers
user=> ; anything we throw
user=> ; we need to be able to catch
user=> (doc catch)
-------------------------
try
  (try expr* catch-clause* finally-clause?)
Special Form
  catch-clause => (catch classname name expr*)
  finally-clause => (finally expr*)

  Catches and handles Java exceptions.

  Please see http://clojure.org/special_forms#try
nil
user=> (try (find-multiple 3 to-ten) (catch Exception xx (println "caught exception %s" xx)))
caught exception %s #
nil
user=> (try (find-multiple 3 to-ten) (catch Exception xx (println "caught exception %s" xx) (println "hit finally")))
caught exception %s #
hit finally
nil
user=> (try (find-multiple 13 to-ten) (catch Exception xx (println "caught exception %s" xx) (println "hit finally")))
nil
user=> ; ah
user=> ; need the magic "finally" incantation
user=> (try (find-multiple 13 to-ten) (catch Exception xx (println "caught exception %s" xx) (finally println "hit finally")))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: finally in this context, compiling:(NO_SOURCE_PATH)
user=> (try (find-multiple 13 to-ten) (catch Exception xx (println "caught exception %s" xx)) (println "hit finally"))
CompilerException java.lang.RuntimeException: Only catch or finally clause can follow catch in try expression, compiling:(NO_SOURCE_PATH)
user=> ; oops, got bracketing wrong
user=>
user=> (try (find-multiple 13 to-ten)
          (catch Exception xx (println "caught exception %s" xx))
          (finally println "hit finally"))
nil
user=> ;
user=> ; hmm, not hitting finally
user=> ; doh, need to make the print statement a proper expression
user=> (try (find-multiple 3 to-ten)
          (catch Exception xx (println "caught exception %s" xx))
          (finally (println "in finally clause")))
caught exception %s #
in finally clause
nil
user=> (try (find-multiple 13 to-ten)
          (catch Exception xx (println "caught exception %s" xx))
          (finally (println "in finally clause")))
in finally clause
nil
user=>

Namespaces

user=> (doc namespace)
-------------------------
clojure.core/namespace
([x])
  Returns the namespace String of a symbol or keyword, or nil if not present.
nil
user=> (namespace x)
ClassCastException java.lang.Long cannot be cast to clojure.lang.Named  clojure.core/namespace (core.clj:1496)
user=> (namespace 'x)
nil
user=> (namespace 'll)
nil
user=> (doc ns)
-------------------------
clojure.core/ns
([name docstring? attr-map? references*])
Macro
  Sets *ns* to the namespace named by name (unevaluated), creating it
  if needed.  references can be zero or more of: (:refer-clojure ...)
  (:require ...) (:use ...) (:import ...) (:load ...) (:gen-class)
  with the syntax of refer-clojure/require/use/import/load/gen-class
  respectively, except the arguments are unevaluated and need not be
  quoted. (:gen-class ...), when supplied, defaults to :name
  corresponding to the ns name, :main true, :impl-ns same as ns, and
  :init-impl-ns true. All options of gen-class are
  supported. The :gen-class directive is ignored when not
  compiling. If :gen-class is not supplied, when compiled only an
  nsname__init.class will be generated. If :refer-clojure is not used, a
  default (refer 'clojure) is used.  Use of ns is preferred to
  individual calls to in-ns/require/use/import:

  (ns foo.bar
    (:refer-clojure :exclude [ancestors printf])
    (:require (clojure.contrib sql sql.tests))
    (:use (my.lib this that))
    (:import (java.util Date Timer Random)
             (java.sql Connection Statement)))
nil
user=> (ns my-namespace)
nil
my-namespace=> *ns*
#
my-namespace=> (dir my-namespace)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: dir in this context, compiling:(NO_SOURCE_PATH)
my-namespace=> (dir 'my-namespace)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: dir in this context, compiling:(NO_SOURCE_PATH)
my-namespace=> (doc import)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: doc in this context, compiling:(NO_SOURCE_PATH)
my-namespace=> ; let me out!
my-namespace=> (ns user)
nil
user=> (doc import)
-------------------------
clojure.core/import
([& import-symbols-or-lists])
Macro
  import-list => (package-symbol class-name-symbols*)

  For each name in class-name-symbols, adds a mapping from name to the
  class named by package.name to the current namespace. Use :import in the ns
  macro in preference to calling this directly.
nil
user=> (ns my-namespace :import clojure.core)
IllegalArgumentException Don't know how to create ISeq from: clojure.lang.Keyword  clojure.lang.RT.seqFrom (RT.java:487)
user=> (ns my-namespace :import (clojure.core))
IllegalArgumentException Don't know how to create ISeq from: clojure.lang.Keyword  clojure.lang.RT.seqFrom (RT.java:487)
user=> (ns my-namespace (:import (clojure.core)))
nil
my-namespace=> (doc dir)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: doc in this context, compiling:(NO_SOURCE_PATH)
my-namespace=> (dir my-namespace)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: dir in this context, compiling:(NO_SOURCE_PATH)
my-namespace=> (ns user)
nil
user=> (doc doc)
-------------------------
clojure.repl/doc
([name])
Macro
  Prints documentation for a var or special form given its name
nil
user=> (ns my-namespace (:import (clojure.core) (clojure.repl)))
nil
my-namespace=> (doc doc)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: doc in this context, compiling:(NO_SOURCE_PATH)
my-namespace=> ; let me out
my-namespace=> (ns user)
nil
user=> (ns my-namespace (:import (clojure.core import) (clojure.repl dir doc)))
ClassNotFoundException clojure.core.import  java.net.URLClassLoader$1.run (URLClassLoader.java:202)
my-namespace=> (ns my-namespace (:import (clojure.core import) (clojure.repl/dir)))
ClassNotFoundException clojure.core.import  java.net.URLClassLoader$1.run (URLClassLoader.java:202)
my-namespace=> (ns my-namespace)
nil
my-namespace=> (import (clojure.repl dir))
ClassNotFoundException clojure.repl.dir  java.net.URLClassLoader$1.run (URLClassLoader.java:202)
my-namespace=> (ns user)
nil
user=> (doc import)
-------------------------
clojure.core/import
([& import-symbols-or-lists])
Macro
  import-list => (package-symbol class-name-symbols*)

  For each name in class-name-symbols, adds a mapping from name to the
  class named by package.name to the current namespace. Use :import in the ns
  macro in preference to calling this directly.
nil
user=> (doc require)
-------------------------
clojure.core/require
([& args])
  Loads libs, skipping any that are already loaded. Each argument is
  either a libspec that identifies a lib, a prefix list that identifies
  multiple libs whose names share a common prefix, or a flag that modifies
  how all the identified libs are loaded. Use :require in the ns macro
  in preference to calling this directly.

  Libs

  A 'lib' is a named set of resources in classpath whose contents define a
  library of Clojure code. Lib names are symbols and each lib is associated
  with a Clojure namespace and a Java package that share its name. A lib's
  name also locates its root directory within classpath using Java's
  package name to classpath-relative path mapping. All resources in a lib
  should be contained in the directory structure under its root directory.
  All definitions a lib makes should be in its associated namespace.

  'require loads a lib by loading its root resource. The root resource path
  is derived from the lib name in the following manner:
  Consider a lib named by the symbol 'x.y.z; it has the root directory
  /x/y/, and its root resource is /x/y/z.clj. The root
  resource should contain code to create the lib's namespace (usually by using
  the ns macro) and load any additional lib resources.

  Libspecs

  A libspec is a lib name or a vector containing a lib name followed by
  options expressed as sequential keywords and arguments.

  Recognized options: :as
  :as takes a symbol as its argument and makes that symbol an alias to the
    lib's namespace in the current namespace.

  Prefix Lists

  It's common for Clojure code to depend on several libs whose names have
  the same prefix. When specifying libs, prefix lists can be used to reduce
  repetition. A prefix list contains the shared prefix followed by libspecs
  with the shared prefix removed from the lib names. After removing the
  prefix, the names that remain must not contain any periods.

  Flags

  A flag is a keyword.
  Recognized flags: :reload, :reload-all, :verbose
  :reload forces loading of all the identified libs even if they are
    already loaded
  :reload-all implies :reload and also forces loading of all libs that the
    identified libs directly or indirectly load via require or use
  :verbose triggers printing information about each load, alias, and refer

  Example:

  The following would load the libraries clojure.zip and clojure.set
  abbreviated as 's'.

  (require '(clojure zip [set :as s]))
nil
user=>  (ns my-namespace (:import (clojure.core import) (clojure.repl dir)))
ClassNotFoundException clojure.core.import  java.net.URLClassLoader$1.run (URLClassLoader.java:202)
my-namespace=>  (ns my-namespace (:import (clojure.core) (clojure.repl dir)))
ClassNotFoundException clojure.repl.dir  java.net.URLClassLoader$1.run (URLClassLoader.java:202)
my-namespace=>  (ns my-namespace (:import (clojure.core) (clojure.repl)))
nil
my-namespace=> (ns user)
nil
user=>  (ns my-namespace (:import (clojure.core) (clojure.repl)))
nil
my-namespace=> (doc dir)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: doc in this context, compiling:(NO_SOURCE_PATH)
my-namespace=> (ns user)
nil
user=> (doc dir)
-------------------------
clojure.repl/dir
([nsname])
Macro
  Prints a sorted directory of public vars in a namespace
nil
user=>  (ns my-namespace (:import (clojure.core) (clojure.repl)))
nil
my-namespace=> (clojure.repl/dir)
ArityException Wrong number of args (0) passed to: repl$dir  clojure.lang.Compiler.macroexpand1 (Compiler.java:6325)
my-namespace=> (clojure.repl/dir my-namespace)
nil
my-namespace=> (def x-in-mine 2)
#'my-namespace/x-in-mine
my-namespace=> (clojure.repl/dir my-namespace)
x-in-mine
nil
my-namespace=> ; OK, looks like a <package>/<symbol> is a fully qualified name
my-namespace=> ; just to confirm expected hiding
my-namespace=> (def x 10)
#'my-namespace/x
my-namespace=> x
10
my-namespace=> (ns user)
nil
user=> (def x 1)
#'user/x
user=> x
1
user=> (ns user)
nil
user=> (ns my-namespace)
nil
my-namespace=> x
10
my-namespace=> ; so how do I make a symbol from another package look like its local
my-namespace=> ; like a Python import?
my-namespace=> (ns temp-namespace)
nil
temp-namespace=> (clojure.repl/dir temp-namespace)
nil
temp-namespace=> ; ok, so I can get at things with an absolute name
temp-namespace=> ; even if there's been no sniff of an import
temp-namespace=> (ns my-namespace)
nil
my-namespace=> (clojure.repl/doc import)
-------------------------
clojure.core/import
([& import-symbols-or-lists])
Macro
  import-list => (package-symbol class-name-symbols*)

  For each name in class-name-symbols, adds a mapping from name to the
  class named by package.name to the current namespace. Use :import in the ns
  macro in preference to calling this directly.
nil
my-namespace=> (import clojure.repl doc)
ClassNotFoundException clojure.repl  java.net.URLClassLoader$1.run (URLClassLoader.java:202)
my-namespace=> (import 'clojure.repl doc)
ClassNotFoundException clojure.repl  java.net.URLClassLoader$1.run (URLClassLoader.java:202)
my-namespace=> (import 'clojure.repl/doc)
ClassNotFoundException doc  java.net.URLClassLoader$1.run (URLClassLoader.java:202)
my-namespace=> (doc require)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: doc in this context, compiling:(NO_SOURCE_PATH)
my-namespace=> (clojure.repl/doc require)
-------------------------
clojure.core/require
([& args])
  Loads libs, skipping any that are already loaded. Each argument is
  either a libspec that identifies a lib, a prefix list that identifies
  multiple libs whose names share a common prefix, or a flag that modifies
  how all the identified libs are loaded. Use :require in the ns macro
  in preference to calling this directly.

  Libs

  A 'lib' is a named set of resources in classpath whose contents define a
  library of Clojure code. Lib names are symbols and each lib is associated
  with a Clojure namespace and a Java package that share its name. A lib's
  name also locates its root directory within classpath using Java's
  package name to classpath-relative path mapping. All resources in a lib
  should be contained in the directory structure under its root directory.
  All definitions a lib makes should be in its associated namespace.

  'require loads a lib by loading its root resource. The root resource path
  is derived from the lib name in the following manner:
  Consider a lib named by the symbol 'x.y.z; it has the root directory
  /x/y/, and its root resource is /x/y/z.clj. The root
  resource should contain code to create the lib's namespace (usually by using
  the ns macro) and load any additional lib resources.

  Libspecs

  A libspec is a lib name or a vector containing a lib name followed by
  options expressed as sequential keywords and arguments.

  Recognized options: :as
  :as takes a symbol as its argument and makes that symbol an alias to the
    lib's namespace in the current namespace.

  Prefix Lists

  It's common for Clojure code to depend on several libs whose names have
  the same prefix. When specifying libs, prefix lists can be used to reduce
  repetition. A prefix list contains the shared prefix followed by libspecs
  with the shared prefix removed from the lib names. After removing the
  prefix, the names that remain must not contain any periods.

  Flags

  A flag is a keyword.
  Recognized flags: :reload, :reload-all, :verbose
  :reload forces loading of all the identified libs even if they are
    already loaded
  :reload-all implies :reload and also forces loading of all libs that the
    identified libs directly or indirectly load via require or use
  :verbose triggers printing information about each load, alias, and refer

  Example:

  The following would load the libraries clojure.zip and clojure.set
  abbreviated as 's'.

  (require '(clojure zip [set :as s]))
nil
my-namespace=> ; that sounds more about loading external libraries from
my-namespace=> ; disk rather than making existing things visible with a shorter name
my-namespace=> (clojure.repl/doc refer)
-------------------------
clojure.core/refer
([ns-sym & filters])
  refers to all public vars of ns, subject to filters.
  filters can include at most one each of:

  :exclude list-of-symbols
  :only list-of-symbols
  :rename map-of-fromsymbol-tosymbol

  For each public interned var in the namespace named by the symbol,
  adds a mapping from the name of the var to the var to the current
  namespace.  Throws an exception if name is already mapped to
  something else in the current namespace. Filters can be used to
  select a subset, via inclusion or exclusion, or to provide a mapping
  to a symbol different from the var's name, in order to prevent
  clashes. Use :use in the ns macro in preference to calling this directly.
nil
my-namespace=> (clojure.core/refer clojure.repl)
CompilerException java.lang.RuntimeException: java.lang.ClassNotFoundException: clojure.repl, compiling:(NO_SOURCE_PATH)
my-namespace=> (clojure.core/refer 'clojure.repl)
nil
my-namespace=> (doc doc)
-------------------------
clojure.repl/doc
([name])
Macro
  Prints documentation for a var or special form given its name
nil
my-namespace=> ; aha
my-namespace=> ; we've got it
my-namespace=>

Introspection

Clojure 1.3.0
user=> ; let's play with introspection
user=> ; define a few things first
user=> ; so we've got a navel to gaze into
user=> ; so when we gaze into our navel
user=> ; we'll at least find some fluff
user=> (def x 1)
#'user/x
user=> (def y 2)
#'user/y
user=> (defn f [x] (+ x y))
#'user/f
user=> (f 5)
7
user=>
user=> (doc help
)
nil
user=> (doc doc)
-------------------------
clojure.repl/doc
([name])
Macro
  Prints documentation for a var or special form given its name
nil
user=> (doc dir)
-------------------------
clojure.repl/dir
([nsname])
Macro
  Prints a sorted directory of public vars in a namespace
nil
user=> *namespace*
CompilerException java.lang.RuntimeException: Unable to resolve symbol: *namespace* in this context, compiling:(NO_SOURCE_PATH)
user=> *ns*
#
user=> (dir *ns*)
Exception No namespace: *ns* found  clojure.core/the-ns (core.clj:3689)
user=> (dir user)
f
x
y
nil
user=> (def ll (dir user))
f
ll
x
y
#'user/ll
user=> ll
nil
user=> ; so 'dir' prints out the symbols in the namespace rather than returning a sequence of them
user=> ; cheat and look up a couple of interesting things
user=> (ns-publics user)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: user in this context, compiling:(NO_SOURCE_PATH)
user=> (ns-publics 'user)
{ll #'user/ll, f #'user/f, x #'user/x, y #'user/y}
user=>
user=>
user=>
user=>
user=>
user=> (type (ns-publics 'user))
clojure.lang.PersistentArrayMap
user=> (def temp (ns-publics 'user))
#'user/temp
user=> (temp :ll)
nil
user=> (temp 'll)
#'user/ll
user=> (type (temp 'x))
clojure.lang.Var
user=> (temp 'f)
#'user/f
user=> (type (temp 'f))
clojure.lang.Var
user=>
user=> (ns-privates user)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: ns-privates in this context, compiling:(NO_SOURCE_PATH)
user=> (ns-interns user)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: user in this context, compiling:(NO_SOURCE_PATH)
user=> (ns-interns 'user)
{temp #'user/temp, ll #'user/ll, f #'user/f, x #'user/x, y #'user/y}
user=> (ns-map 'user)
{sorted-map #'clojure.core/sorted-map, read-line #'clojure.core/read-line, re-pattern #'clojure.core/re-pattern,
...snip...
Runtime java.lang.Runtime, keep #'clojure.core/keep, disj! #'clojure.core/disj!, meta #'clojure.core/meta}
user=> ; yikes
user=> ; that's including all of the imported/external stuff
user=>
user=> ; looking around on teh internet
user=> ; there's a useful Clojure script here
user=> ; with various tips and useful utils embedded therein

Java Interop

Clojure 1.3.0
user=> ;
user=> ; so the J in clojure comes from Java
user=> ; and we've seen a lot of mention of Java objects
user=> ; so let's see what we can get access to
user=> (type "fred")
java.lang.String
user=> (def x (java.lang.String 1))
ClassCastException java.lang.Class cannot be cast to clojure.lang.IFn  clojure.lang.Compiler$InvokeExpr.eval (Compiler.java:3333)
user=> (doc java.lang.Integer)
CompilerException java.lang.RuntimeException: Unable to resolve var: java.lang.Integer in this context, compiling:(NO_SOURCE_PATH)
user=> (doc java.lang)
ClassNotFoundException java.lang  java.net.URLClassLoader$1.run (URLClassLoader.java:202)
user=> ; first of all, how do I create a Java object?
user=> (doc Integer)
CompilerException java.lang.RuntimeException: Expecting var, but Integer is mapped to class java.lang.Integer, compiling:(NO_SOURCE_PATH)
user=> (doc java.lang/Integer)
nil
user=> (Integer 2)
RuntimeException Expecting var, but Integer is mapped to class java.lang.Integer  clojure.lang.Util.runtimeException (Util.java:156)
user=>
user=> ; cheat and look up the magic dot macro
user=> (. Integer 2)
CompilerException java.lang.IllegalArgumentException: Malformed member expression, compiling:(NO_SOURCE_PATH)
user=> (new Integer)
CompilerException java.lang.IllegalArgumentException: No matching ctor found for class java.lang.Integer, compiling:(NO_SOURCE_PATH)
user=> (new Integer 2)
2
user=> ; aha
user=> (doc new)
-------------------------
new
  (Classname. args*)
  (new Classname args*)
Special Form
  The args, if any, are evaluated from left to right, and
  passed to the constructor of the class named by Classname. The
  constructed object is returned.

  Please see http://clojure.org/java_interop#new
nil
user=> (def i2 (new Integer 2))
#'user/i2
user=> i2
2
user=> ; presumably other constructors are similar
user=> (def i3 (new Integer "32"))
#'user/i3
user=> i3
32
user=> ; how do we invoke a method on an object?
user=> (i3 toHexString)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: toHexString in this context, compiling:(NO_SOURCE_PATH)
user=> (java.lang.Integer/toHexString i3)
"20"
user=> ; well that works, but it's a bit long-winded (** actually, not quite -- see below **)
user=> ; is there any syntactic sugar to make it a bit sweeter?
user=>
user=> ;
user=> (. i3 toHexString)
IllegalArgumentException No matching field found: toHexString for class java.lang.Integer  clojure.lang.Reflector.getInstanceField (Reflector.java:289)
user=> (.toHexString i3)
IllegalArgumentException No matching field found: toHexString for class java.lang.Integer  clojure.lang.Reflector.getInstanceField (Reflector.java:289)
user=> (type i3)
java.lang.Integer
user=> (. i3 toHexString)
IllegalArgumentException No matching field found: toHexString for class java.lang.Integer  clojure.lang.Reflector.getInstanceField (Reflector.java:289)
user=> (doc .)
-------------------------
.
  (.instanceMember instance args*)
  (.instanceMember Classname args*)
  (Classname/staticMethod args*)
  Classname/staticField
Special Form
  The instance member form works for both fields and methods.
  They all expand into calls to the dot operator at macroexpansion time.

  Please see http://clojure.org/java_interop#dot
nil
user=> (.toHexString i3)
IllegalArgumentException No matching field found: toHexString for class java.lang.Integer  clojure.lang.Reflector.getInstanceField (Reflector.java:289)
user=> (. toHexString i3)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: toHexString in this context, compiling:(NO_SOURCE_PATH)
user=> (.intValue i3)
32
user=> ; doh
user=> ; toHexString is a static method
user=> ; so just (.<methodname> <self> <args*>) is method invocation
user=> ; speaking of which, we've seen how to get at static methods
user=> (java.lang.Integer/toHexString 100)
"64"
user=> ; turns out there's another way too
user=> (. java.lang.Integer toHexString 100)
"64"
user=>
user=> ; how about a more realistic example
user=> (def abpattern (. java.util.regexp.Pattern compile "a*b"))
CompilerException java.lang.RuntimeException: java.lang.ClassNotFoundException: java.util.regexp.Pattern, compiling:(NO_SOURCE_PATH)
user=> (def abpattern (. java.util.regex.Pattern compile "a*b"))
#'user/abpattern
user=> (type abpattern)
java.util.regex.Pattern
user=> abpattern
#"a*b"
user=> ; ooh, interesting
user=> ; looks like there's some syntactic sugar
user=> #"a*b*c"
#"a*b*c"
user=> (type #"a*b*c")
java.util.regex.Pattern
user=> ; useful
user=> (def m (.matcher abpattern "aaaaab"))
#'user/m
user=> (type m)
java.util.regex.Matcher
user=> m
#
user=> (.matches m)
true
user=> (def m (.matcher abpattern "ccccb"))
#'user/m
user=> (.matches m)
false

Copyright (c) 2012, David Drysdale

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is available here.


Back to Home Page | Contact me