Functions are first-class values that implement the IFn interface (and also Java's Callable, Runnable and Comparator). A function is made by the special form fn; defn is the macro that makes one and binds it to a global var.
fn and defn
| Form | Meaning |
|---|---|
(fn name? [params*] expr*) | a function with one arity. The optional name is bound inside the body to the function itself, so even an anonymous function can call itself |
(fn name? ([params*] expr*)+) | several arities, overloaded on the number of arguments (0 to 20 fixed, plus one variadic). The arities must be distinct; one and only one may be variadic |
(defn name doc-string? attr-map? [params*] condition-map? expr*) | defines a var holding a function. The attribute map and any metadata on the name are put on the var; :arglists is recorded. defn- makes a private var |
(defn name doc-string? attr-map? ([params*] …)+ attr-map?) | the multi-arity form |
#(… % %2 %&) | a function literal: a short fn whose parameters are % or %1, %2 … and %& for the rest. It cannot be nested |
Parameters are binding forms: a symbol or a destructuring form. A & before the last parameter collects the remaining arguments in a seq (nil if there are none). A type hint such as ^String s on a parameter is used by the compiler. Each arity is a recursion point for recur, with as many arguments as the parameters, counting the rest parameter.
(def mult
(fn this
([] 1)
([x] x)
([x y] (* x y))
([x y & more]
(apply this (this x y) more))))
Pre- and post-conditions
Since Clojure 1.1 a function body may start with a map of conditions: {:pre [pre-expr*] :post [post-expr*]}. In a post-condition % is the return value. If a condition is false and *assert* is true, a java.lang.AssertionError is thrown. The map may also be metadata of the argument vector. If the only form after the parameters is a map, it is the body, not the conditions.
(defn constrained-sqr [x]
{:pre [(pos? x)]
:post [(> % 16), (< % 225)]}
(* x x))
Keyword arguments
Optional trailing arguments of the form :a 1 :b 2 are received by a map destructuring form in the rest-parameter position: (defn f [x & {:keys [a b] :as opts}] …). Since Clojure 1.11 such a function may also be called with one map instead of, or after, the key-value pairs: (f 1 {:a 1 :b 2}). A lone map is used as it is; otherwise a trailing map is merged into the map built from the pairs.
Higher-order functions
| Function | Does |
|---|---|
apply | (apply f a b [c d]) calls f with the arguments, the last being a collection of more |
partial | fixes leading arguments |
comp | composes right to left: ((comp f g) x) is (f (g x)) |
juxt | ((juxt f g) x) is [(f x) (g x)] |
complement, constantly, identity | negate a predicate; always return one value; return the argument |
fnil | replaces a nil argument with a default |
every-pred, some-fn | combine predicates with and and or |
memoize | caches results by arguments |
trampoline | runs a function that returns functions until a non-function is returned, for mutual recursion |
fn?, ifn? | test for a function; for anything callable |
Binding forms: destructuring
A binding form is a symbol, or a vector or map that takes a collection apart. Destructuring works wherever a binding form is allowed: let, fn and defn parameters, loop, for and doseq, and every macro that expands to let or fn. Parts that have no data bind to nil, and forms nest to any depth.
Sequential (vector) forms
A vector binds by position in anything that supports nth: vectors, lists, seqs, strings, arrays. & binds the rest (looked up with nthnext) and :as binds the whole.
(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]]
(let [[[x1 y1] [x2 y2]] [[1 2] [3 4]]]
[x1 y1 x2 y2])
;; => [1 2 3 4]
Associative (map) forms
A map binds each binding-form to the value at a key, in anything that supports get: maps, sets, vectors, strings and arrays (the last three with integer keys). The special keys are:
| Key | Value | Effect |
|---|---|---|
:as | a symbol | binds the whole value |
:or | a map of name to default | values for keys that are absent from the input; the example below gives a and b defaults |
:keys | a vector of symbols or keywords | {:keys [a b]} is {a :a, b :b}. Qualified entries (x/a, or ::x) look up the qualified key and bind the plain name |
:strs | a vector of symbols | looks up string keys: {:strs [a]} is {a "a"} |
:syms | a vector of symbols | looks up symbol keys; may be qualified |
:ns/keys, :ns/syms | a vector of unqualified names | Clojure 1.9: every key gets the namespace ns: {:domain/keys [a b]} |
(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}]
(let [m #:domain{:a 1, :b 2}
{:domain/keys [a b]} m]
[a b])
;; => [1 2]
The destructuring page of the Clojure site documents, for the release after 1.12, further directives that were not in a released version of the changes list that was read (changes.md ends at 1.12.6): :keys! :strs! :syms! (checked: they throw if a key is missing), & inside a :keys vector to name keys that are required or documented but not bound, :select (a map limited to the keys named) and :all (the input with defaults filled in). The page marks them "since 1.13". The viewer colours them as destructuring keys.
Where destructuring is used
letandloopbindings,foranddoseqbindings;fnanddefnparameter vectors, including each arity of a multi-arity function;- the macros built on them:
when-let,if-let,dotimes(a symbol only),with-open,binding(vars, no destructuring) and your own macros that expand tolet.
Not described
Known, not yet covered
- Reference: the destructuring guide (
destructuring.adoc) was read only through its headings; the page above follows the reference page on special forms. Primitive function signatures (^longparameters,IFn$LLand up to four primitive parameters) and the 20-argument arity limit are not described in detail. - Viewer: a local that shadows a core function (a parameter named
count) is coloured as a variable where it is bound, but a later use of it is coloured as the core function, because the viewer does not track scopes.
Unknown
- Reference: the 1.13 destructuring directives are described only from the web page; no 1.13 release was available to check them.
See also
- Evaluation and special forms –
let,loopandrecur - Macros and syntax-quote –
defmacrouses the same parameter forms - Racket: functions and keyword arguments – the Racket equivalent