Clojure

Special Forms

Special forms have evaluation rules that differ from standard Clojure evaluation rules and are understood directly by the Clojure compiler.

Headings for the special forms informally describe the special form grammar using regular expression syntax: ? (optional), * (0 or more), and + (1 or more). Non-terminals are denoted by italics.

(def symbol doc-string? init?)

Creates and interns or locates a global var with the name of symbol and a namespace of the value of the current namespace (*ns*). If init is supplied, it is evaluated, and the root binding of the var is set to the resulting value. If init is not supplied, the root binding of the var is unaffected. def always applies to the root binding, even if the var is thread-bound at the point where def is called. def yields the var itself (not its value). Throws an exception if symbol is already in the namespace and not mapped to an interned var. Support for doc-string was added in Clojure 1.3.

Any metadata on the symbol will be evaluated, and become metadata on the var itself. There are several metadata keys that have special interpretation:

  • :private

    a boolean indicating the access control for the var. If this key is not present, the default access is public (e.g. as if :private false).

  • :doc

    a string containing short (1-3 line) documentation for the var contents

  • :test

    a fn of no args that uses assert to check various operations. The var itself will be accessible during evaluation of a literal fn in the metadata map.

  • :tag

    a symbol naming a class or a Class object that indicates the Java type of the object in the var, or its return value if the object is a fn.

In addition the compiler will place the following metadata keys on the var:

  • :file string

  • :line int

  • :name simple symbol

  • :ns namespace in which var is interned

  • :macro true if var names a macro

  • :arglists a list of vector(s) of argument forms, as were supplied to defn

The var metadata can be used for application-specific purposes as well. Consider using namespace-qualified keys (e.g. :myns/foo) to avoid clashes.

(defn
 ^{:doc "mymax [xs+] gets the maximum value in xs using > "
   :test (fn []
             (assert (= 42  (mymax 2 42 5 4))))
   :user/comment "this is the best fn ever!"}
  mymax
  ([x] x)
  ([x y] (if (> x y) x y))
  ([x y & more]
   (reduce mymax (mymax x y) more)))

user=> (meta #'mymax)
  {:name mymax,
   :user/comment "this is the best fn ever!",
   :doc "mymax [xs+] gets the maximum value in xs using > ",
   :arglists ([x] [x y] [x y & more])
   :file "repl-1",
   :line 126,
   :ns #<Namespace user >,
   :test #<user$fn__289 user$fn__289@20f443 >}

Many macros expand into def (e.g. defn, defmacro), and thus also convey metadata for the resulting var from the symbol used as the name.

Using def to modify the root value of a var at other than the top level is usually an indication that you are using the var as a mutable global, and is considered bad style. Consider either using binding to provide a thread-local value for the var, or putting a ref or agent in the var and using transactions or actions for mutation.

(if test then else?)

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. All of the other conditionals in Clojure are based upon the same logic, that is, nil and false constitute logical falsity, and everything else constitutes logical truth, and those meanings apply throughout. if performs conditional tests of boolean Java method return values without conversion to Boolean. Note that if does not test for arbitrary values of java.lang.Boolean, only the singular value false (Java’s Boolean.FALSE), so if you are creating your own boxed Booleans make sure to use Boolean/valueOf and not the Boolean constructors.

(do expr*)

Evaluates the expressions exprs in order and returns the value of the last. If no expressions are supplied, returns nil.

(let [ binding* ] expr*)

bindingbinding-form init-expr

Evaluates the expressions exprs in a lexical context in which the symbols in the binding-forms are bound to their respective init-exprs or parts therein. The bindings are sequential, so each binding can see the prior bindings. The exprs are contained in an implicit do. If a binding symbol is annotated with a metadata tag, the compiler will try to resolve the tag to a class name and presume that type in subsequent references to the binding. The simplest binding-form is a symbol, which is bound to the entire init-expr:

(let [x 1
      y x]
  y)
-> 1

If the binding symbol :tag metadata is a Java interface annotated as a FunctionalInterface, the init-expr will be coerced (if necessary) to the specified interface:

(let [coll (java.util.ArrayList. (range 10))
      ^java.util.function.Predicate pred even?]
  (.removeIf coll pred) ;; mutate coll
  coll)
-> [1 3 5 7 9]

See Binding Forms for more information about binding forms.

Locals created with let are not variables. Once created their values never change!

(quote form)

Yields the unevaluated form.

user=> '(a b c)
(a b c)

Note there is no attempt made to call the function a. The return value is a list of 3 symbols.

(var symbol)

The symbol must resolve to a var, and the Var object itself (not its value) is returned. The reader macro #'x expands to (var x).

(fn name? [params* ] expr*)

(fn name? ([params* ] expr*)+)

paramspositional-param* , or positional-param* & rest-param
positional-parambinding-form
rest-parambinding-form
namesymbol

Defines a function (fn). Fns are first-class objects that implement the IFn interface. The IFn interface defines an invoke() function that is overloaded with arity ranging from 0-20. A single fn object can implement one or more invoke methods, and thus be overloaded on arity. One and only one overload can itself be variadic, by specifying the ampersand followed by a single rest-param. Such a variadic entry point, when called with arguments that exceed the positional params, collects them in a seq which is bound to, or destructured by, the rest param. If the supplied args do not exceed the positional params, the rest param will be nil.

The first form defines a fn with a single invoke method. The second defines a fn with one or more overloaded invoke methods. The arities of the overloads must be distinct. In either case, the result of the expression is a single fn object.

The expressions exprs are compiled in an environment in which the params are bound to the actual arguments. The exprs are enclosed in an implicit do. If a name symbol is provided, it is bound within the function definition to the function object itself, allowing for self-calling, even in anonymous functions. If a param symbol is annotated with a metadata tag, the compiler will try to resolve the tag to a class name and presume that type in subsequent references to the binding.

(def mult
  (fn this
      ([] 1)
      ([x] x)
      ([x y] (* x y))
      ([x y & more]
          (apply this (this x y) more))))

Note that named fns such as mult are normally defined with defn, which expands into something such as the above.

A fn (overload) defines a recursion point at the top of the function, with arity equal to the number of params including the rest param, if present. See recur.

fns implement the Java Callable, Runnable and Comparator interfaces.

Since 1.1

Functions support specifying runtime pre- and post-conditions.

The syntax for function definitions becomes the following:

(fn name? [param* ] condition-map? expr*)

(fn name? ([param* ] condition-map? expr*)+)

The syntax extension also applies to defn and other macros which expand to fn forms.

Note: If the sole form following the parameter vector is a map, it is treated as the function body, and not the condition map.

The condition-map parameter may be used to specify pre- and post-conditions for a function. It is of the following form:

{:pre [pre-expr*]
 :post [post-expr*]}

where either key is optional. The condition map may also be provided as metadata of the arglist.

pre-expr and post-expr are boolean expressions that may refer to the parameters of the function. In addition, % may be used in a post-expr to refer to the function’s return value. If any of the conditions evaluate to false and *assert* is true, a java.lang.AssertionError exception is thrown.

Example:

(defn constrained-sqr [x]
    {:pre  [(pos? x)]
     :post [(> % 16), (< % 225)]}
    (* x x))

See Binding Forms for more information about binding forms.

(loop [binding* ] expr*)

loop is exactly like let, except that it establishes a recursion point at the top of the loop, with arity equal to the number of bindings. See recur.

(recur expr*)

Evaluates the expressions exprs in order, then, in parallel, rebinds the bindings of the recursion point to the values of the exprs. If the recursion point was a fn method, then it rebinds the params. If the recursion point was a loop, then it rebinds the loop bindings. Execution then jumps back to the recursion point. The recur expression must match the arity of the recursion point exactly. In particular, if the recursion point was the top of a variadic fn method, there is no gathering of rest args - a single seq (or null) should be passed. recur in other than a tail position is an error.

Note that recur is the only non-stack-consuming looping construct in Clojure. There is no tail-call optimization and the use of self-calls for looping of unknown bounds is discouraged. recur is functional and its use in tail-position is verified by the compiler.

(def factorial
  (fn [n]
    (loop [cnt n acc 1]
       (if (zero? cnt)
            acc
          (recur (dec cnt) (* acc cnt))))))

(throw expr)

The expr is evaluated and thrown, therefore it should yield an instance of some derivee of Throwable.

(try expr* catch-clause* finally-clause?)

catch-clause → (catch classname name expr*)
finally-clause → (finally expr*)

The exprs are evaluated and, if no exceptions occur, the value of the last expression is returned. If an exception occurs and catch-clauses are provided, each is examined in turn and the first for which the thrown exception is an instance of the classname is considered a matching catch-clause. If there is a matching catch-clause, its exprs are evaluated in a context in which name is bound to the thrown exception, and the value of the last is the return value of the function. If there is no matching catch-clause, the exception propagates out of the function. Before returning, normally or abnormally, any finally-clause exprs will be evaluated for their side effects.

(monitor-enter expr)

(monitor-exit expr)

These are synchronization primitives that should be avoided in user code. Use the locking macro.

Other Special Forms

The special forms dot ('.'), new, and set! of fields are described in the Java Interop section of the reference.

set! of vars is described in the Vars section of the reference.

Binding Forms (Destructuring)

The simplest binding-form in Clojure is a symbol. However, Clojure also supports abstract structural binding called destructuring in let binding lists, fn parameter lists, and by extension any macro that expands into a let or fn. Destructuring is a way to create a set of bindings to values within a collection by using an analogous collection as a binding form. A vector form specifies bindings by position in a sequential collection, a map form by key in an associative collection. Destructuring forms can appear anywhere binding-forms can, and thus nest, yielding code that is clearer than using collection accessors.

Binding-forms that don’t match their respective part due to an absence of data (i.e. too few elements in a sequential structure, no key in an associative structure, etc) bind to nil.

Sequential destructuring

Vector binding_forms sequentially bind values in collections like vectors, lists, seqs, strings, arrays, and anything that supports nth. The sequential destructuring form is a vector of binding-forms, which will be bound to successive elements from the init-expr, looked up via nth. In addition, and optionally, a binding-form following a & will be bound to the remainder of the sequence, i.e. that part not yet bound, and looked up via nthnext.

Finally, also optionally, :as followed by a symbol binds that symbol to the entire init-expr:

(let [[a b c & d :as e] [1 2 3 4 5 6 7]]
  [a b c d e])

->[1 2 3 (4 5 6 7) [1 2 3 4 5 6 7]]

These forms can nest:

(let [[[x1 y1][x2 y2]] [[1 2] [3 4]]]
  [x1 y1 x2 y2])

->[1 2 3 4]

In all of the sequential cases the binding-forms in the destructure binding will match the places in the target data structure where the desired values reside.

Associative destructuring

Map binding-forms create bindings by looking up values in collections like maps, sets, vectors, strings, and arrays (the latter three have integer keys). It consists of a map of binding-form→key pairs, each binding-form bound to the value in the init-expr at the key provided. In addition, and optionally, an :as key in the binding form followed by a symbol binds that symbol to the entire init-expr. Also optionally, an :or key in the binding form followed by another map may be used to supply default values for some or all of the keys if they are not found in the init-expr:

(let [{a :a, b :b, c :c, :as m :or {a 2 b 3}}  {:a 5 :c 6}]
  [a b c m])

->[5 3 6 {:c 6, :a 5}]

It is often the case that you will want to bind symbols with the same name as the corresponding map keys. The :keys directive addresses the redundancy often found in the binding binding-form→key pairs:

(let [{fred :fred ethel :ethel lucy :lucy} m] ...

can be written:

(let [{:keys [fred ethel lucy]} m] ...

As of Clojure 1.6, you can also use prefixed map keys in the map destructuring form:

(let [m {:x/a 1, :y/b 2}
      {:keys [x/a y/b]} m]
  (+ a b))

-> 3

In the case of using prefixed keys, the bound symbol name is the same as the right-hand side of the prefixed key. You can also use auto-resolved keyword forms in the :keys directive:

(let [m {::x 42}
      {:keys [::x]} m]
  x)

-> 42

There are similar :strs and :syms directives for matching string and symbol keys, the latter also allowing prefixed symbol keys since Clojure 1.6.

Clojure 1.9 adds support for directly destructuring many keys (or symbols) that share the same namespace using the following destructuring key forms:

  • :ns/keys - ns specifies the default namespace for the key to look up in the input

    • keys elements should not specify a namespace

    • keys elements also define new local symbols, as with :keys

  • :ns/syms - ns specifies the default namespace for the symbol to look up in the input

    • syms elements should not specify a namespace

    • syms elements also define new local symbols, as with :syms

(let [m #:domain{:a 1, :b 2}
      {:domain/keys [a b]} m]
  [a b])

-> [1 2]

Keyword Arguments

Keyword arguments are optional trailing variadic arguments of the form akey aval bkey bval…​ that can be accessed in the function body via associative destructuring. Also, introduced in Clojure 1.11, a function specified to take kwargs may be passed a single map instead of or in addition to (and following) the key/value pairs. When a lone map is passed, it is used outright for destructuring, else a trailing map is added to the map built from the preceding key/values via conj. To define a function that accepts keyword arguments you supply a map destructuring form in the rest-param declaration position. For example, a function that takes a sequence and optional keyword arguments and returns a vector containing the values is defined as:

(defn destr [& {:keys [a b] :as opts}]
  [a b opts])

(destr :a 1)
->[1 nil {:a 1}]

(destr {:a 1 :b 2})
->[1 2 {:a 1 :b 2}]

The map binding-form to the right of the & in destr is an associative destructuring binding-form detailed above.

The two declarations of foo below are equivalent, demonstrating associative destructuring’s interpretation of seqs:

(defn foo [& {:keys [quux]}] ...)

(defn foo [& opts]
  (let [{:keys [quux]} opts] ...))

Nested destructuring

Since binding forms can be nested within one another arbitrarily, you can pull apart just about anything:

(let [m {:j 15 :k 16 :ivec [22 23 24 25]}
      {j :j, k :k, i :i, [r s & t :as v] :ivec, :or {i 12 j 13}} m]
  [i j k r s t v])

-> [12 15 16 22 23 (24 25) [22 23 24 25]]