Language: clojure.core
This guide covers:
- Key functions of
clojure.core
- Key macros of
clojure.core
- Key vars of
clojure.core
- Essential special forms
This guide is by no means comprehensive and does not try to explain each function/macro/form in depth. It is an overview, the goal is to briefly explain the purpose of each item and provide links to other articles with more information.
This work is licensed under a Creative Commons Attribution 3.0 Unported License (including images & stylesheets). The source is available on Github.
What Version of Clojure Does This Guide Cover?
This guide covers Clojure 1.11.
Binding
let
(let [bindings*] exprs*)
let
takes a vector of symbol/expression pairs (bindings) followed by a variable number of expressions.
let
allows binding of locals (roughly equivalent to variables in many other languages), and evaluates the expressions (with those bindings in scope).
The body of a let
statement also provides an implicit do
that allows for multiple statements in the body of let
.
A basic example:
(let [x 1 y 2]
(println x y))
let
does its bindings sequentially, meaning it's possible to reference previous bindings:
(let [a 5
b (* a 2)
c (+ a b)]
(println "c is" c))
let
can also be nested, and the scope is lexically determined. This means that a binding's value is determined by the nearest binding form for that symbol.
This example demonstrates the lexical scoping of the let form.
(let [x 1]
(println x) ; prints 1
(let [x 2]
(println x)) ; prints 2
(println x)) ; outside the nested let, prints 1 again
let
bindings are immutable and can be destructured.
See: Sections about destructuring in Introduction and Functions pages.
def
(def symbol doc-string? init?)
def
takes a symbol, an optional docstring, and an optional init value
(although it is very rare that you would omit the init value), and creates
(or re-assigns) a var in the current namespace with the name of the symbol.
If an init value is supplied, the root binding of the var is assigned to that
value. Redefining a var with an init value will re-assign the root binding.
If no init value is supplied and the var is newly-created, it will be 'unbound',
otherwise the var already exists and its value is unchanged.
A root binding is a value that is shared across all threads.
(def x)
x ; x is an 'unbound' var, or nil in clojurescript
; => #object [clojure.lang.Var$Unbound 0x1de19fc6 "Unbound: #'user/x"]
(def x 7)
x ; x is now 7
; => 7
(def x)
x ; x is still 7, deffing with no value doesn't unbind an existing value
; => 7
def vs let
Superficially, def
and let
both give names to values. A key difference is that let
bindings are scoped and don't have a namespace, while vars created with def
are 'global' and qualified to a namespace. A name/binding that should only exist within (for example) a function should be created with let
, and it's very rarely needed/advisable to use def
within a function or other form.
; def creates (and returns) vars in the current namespace
(def my-secret-number 5)
(def my-secret-string "hi")
(let [my-secret-number 7] ; this is a local that's not available outside the let block
(vector my-secret-number cljs.user/my-secret-number my-secret-string))
In the output of this example:
my-secret-number
resolves to the local from the surroundinglet
cljs.user/my-secret-number
resolves to the var created bydef
(because thelet
binding doesn't have a namespace)my-secret-string
resolves to the var - since there's no local namedmy-secret-string
, clojure looks for bindings available in the current namespace.
See Vars and the Global Environment in the official Clojure reference documentation for more details, which also covers how to attach metadata to such Vars.
declare
(declare names*)
declare
takes zero or more symbols and behaves as if you had used def
on
each without an init value.
declare
provides a simple way of creating 'forward declarations'.
This allows for referencing of a var before it has been supplied a value.
There are much better methods of value-based dispatch or code architecture in general, but this presents a simple situation forward declarations would be necessary.
(declare func<10 func<20)
;; without declare you will receive an error similar to:
;; "Unable to resolve symbol: func10 in this context"
(defn func<10 [x]
(cond
(< x 10) (func<10 (inc x))
(< x 20) (func<20 x)
:else "too far!"))
(defn func<20 [x]
(cond
(< x 10) (func<10 x)
(< x 20) "More than 10, less than 20"
:else "too far!"))
No matter which order you put func<10 and func<20 in, there will be a reference to a var that does not yet exist when the compiler does the initial evaluation of top-level forms.
declare
defines the var with no binding so that the the var exists when it is referenced later in the code.
defn
(defn name doc-string? attr-map? [params*] prepost-map? body)
(defn name doc-string? attr-map? ([params*] prepost-map? body)+ attr-map?)
defn
takes a symbol, an optional doc string, an optional meta-data
map, a vector of arguments and a variable number of expressions.
defn
is the primary way of defining functions. It allows for
convenient definition of metadata about its argslist and documentation
(docstrings). defn
inherently allows for quick documentation of
functions that can be retrieved with doc
. This feature should be
used almost universally.
(defn func [x]
x)
(func 7)
Because defn
has multiple forms and a handful of optional parameters, there's a separate section
that does a deep dive on defining functions.
See the def
Special Form
for more detail about how defn
provides additional metadata and convenience
over def
.
Branching/Grouping
do
(do exprs*)
do
is used to 'group' expressions together. It executes the expressions in order and returns the return value of
the final expression. It is often used when it's necessary to treat multiple expressions as one 'block', like an argument to if
.
if
(if test then else?)
if
takes two or three expressions -- a condition expression, a 'then' expression, and optionally an 'else' expression. If the 'else' expression is not supplied, it defaults to nil
.
if
is the primary method of conditional execution, and other conditionals are built upon if
.
The condition is evaluated, and if its value is truthy -- anything except nil
or false
-- the 'then' expression is evaluated and the result returned
(the 'else' expression is not evaluated).
If the condition returns nil
or
false
the 'else' expression is evaluated and returned
(the 'then' expression is not evaluated).
(if 0 "second") ; 0 is a 'true' value. Only false or nil are 'false'
(if nil "second" "third")
(if (< 10 9) "second" "third") ; (< 10 9) returns false
; seq returns nil for an empty sequence,
; so the third expression (defaulted to nil) is returned
(if (seq '()) "second")
(if (nil? (= 1 2)) "second" "third") ; differentiate between nil and false if needed
; to do multiple things based on the condition, use a `do`
(if (> 4 3)
(do
(println "4 is greater than 3...")
(println "so 3 is less than 4")
"4!")
(println "Uh oh, math is broken."))
when
(when test body*)
when
takes a test and zero or more body
expressions. If the test returns a truthy
value, all the body
expressions are evaluated in an implicit do
, and the last return
value is the return value of when
. If the test is not truthy, nil
is returned (the
body expressions are not evaluated at all).
Put another way, (when test body)
is transformed to (if test (do body))
.
;; (= 1 2) is false so the other expressions are not evaluated
(when (= 1 2) (println "hey") 10)
;; (< 10 11) is true so both expressions are evaluated and the last value returned
(when (< 10 11) (println "hey") 10)
There might be some unfamiliar syntax, but this demo shows that the when
is transformed to an if
expression (this is an example of a macro).
(macroexpand '(when (< 3 4) (println "true text") (println "more true text")))
Looping
recur
(recur exprs*)
recur
allows for self-recursion without consuming stack space proportional to the number of recursive calls made. Due to the lack of tail-call optimization on the JVM currently, this is the only method of recursion that does not consume excess stack space.
recur
takes a number of arguments identical to the point of recursion. recur
will evaluate those arguments, rebind them at the point of recursion and resume execution at that point.
The point of recursion is the nearest function (defn
, fn
) or loop
form determined lexically.
recur
must be in the tail position of the recursion point expression. The tail position is the point in the expression where a return value would otherwise be determined.
recur
does not bind &
in variadic functions and in these situations an empty seq must be passed by recur
.
(defn count-up
[result x y]
(if (= x y)
result
(recur (conj result x) (inc x) y)))
(count-up [] 0 10)
Example: getting factorial of a positive integer:
(defn factorial
([n]
(factorial n 1))
([n acc]
(if (zero? n)
acc
(recur (dec n) (* n acc)))))
(factorial 10)
;; ⇒ 3628800
loop
(loop [bindings*] exprs*)
loop
takes a vector of symbol value pairs followed by a variable number of expressions.
loop
establishes a recursion point for a recur
expression inside its body. loop
provides an implicit let
for bindings.
The implicit let
that loop
provides binds each symbol to the init-expression. recur
then binds new values when returning the execution point to loop
.
(defn count-up
[start total]
(loop [result []
x start
y total]
(if (= x y)
result
(recur (conj result x) (inc x) y))))
(count-up 0 10)
;; ⇒ [0 1 2 3 4 5 6 7 8 9]
Example: getting factorial of a positive integer:
(defn factorial
[n]
(loop [n n
acc 1]
(if (zero? n)
acc
(recur (dec n) (* acc n)))))
(factorial 10)
;; ⇒ 3628800
trampoline
([f])
([f & args])
trampoline
takes a function and a variable number of arguments to pass to that function.
trampoline
allows for mutual recursion without consuming stack space proportional to the number of recursive calls made.
If the return value of that function is a function, trampoline
calls that function with no arguments. If the return value is not a function, trampoline
simply returns that value.
Since trampoline
calls the returned functions with no arguments, you must supply an anonymous function that takes no arguments and calls the function you wish to recur to. This is usually done with anonymous function literals #()
(declare count-up1 count-up2) ;; see `declare` for why this is needed
(defn count-up1
[result start total]
(if (= start total)
result
#(count-up2 (conj result start) (inc start) total))) ;; returns an anonymous function
(defn count-up2 [result start total]
(if (= start total)
result
#(count-up1 (conj result start) (inc start) total))) ;; returns an anonymous function
;; delete #_ to run the example:
#_(trampoline count-up1 [] 0 10)
;; ⇒ [0 1 2 3 4 5 6 7 8 9]
for
([seq-exprs body-expr])
for
takes a vector of pairs of [binding collection].
for
allows for list comprehensions. for
assigns each sequential value in the collection to the binding form and evaluates them rightmost first. The results are returned in a lazy sequence.
for
allows for explicit let, when and while through use of :let []
, :when (expression)
, and :while (expression)
in the binding vector.
(for [x [1 2 3] y [4 5 6]]
[x y])
;; ⇒ ([1 4] [1 5] [1 6] [2 4] [2 5] [2 6] [3 4] [3 5] [3 6])
:when
only evaluates the body when a truthy value is returned by the expression provided
(for [x [1 2 3] y [4 5 6]
:when (and
(even? x)
(odd? y))]
[x y])
;; ⇒ ([2 5])
:while
evaluates the body until a falsey value is reached. Note that elements of the second collection are bound to y
before a falsey value of (< x 2)
is reached in the following example. This demonstrates the order of the comprehension.
(for [x [1 2 3] y [4 5 6]
:while (< x 2)]
[x y])
;; ⇒ ([1 4] [1 5] [1 6])
doseq
([seq-exprs & body])
doseq
takes a vector of pairs of [binding collection]
and then one or more expressions as the body
.
doseq
is similar to for
except it does not return a sequence of results. doseq
is generally intended for execution of side-effects in the body, and thus returns nil
.
doseq
supports the same bindings as for - :let
, :when
, :while
. For examples of those, see for
above.
(doseq [x [1 2 3] y [4 5 6]]
(println [x y]))
;; [1 4][1 5][1 6][2 4][2 5][2 6][3 4][3 5][3 6]
;; ⇒ nil
run!
([proc coll])
If you have a single collection to loop over, just for side-effects,
and a single function to call on each element, you might prefer to use
run!
instead of doseq
. The following are equivalent:
(doseq [x [1 2 3]]
(println x))
(run! println [1 2 3])
iterate
([f x])
iterate
takes a function and an argument to the function.
A lazy sequence is returned consisting of the argument then each subsequent entry is the function evaluated with the previous entry in the lazy sequence. In other words, the function is applied repeatedly to produce each new entry in the sequence.
Since it is an infinite sequence, you need to use take
or similar to get a finite number of elements.
(take 10 (iterate inc 0))
;; ⇒ (0 1 2 3 4 5 6 7 8 9)
reduce
([f coll])
([f val coll])
reduce
takes a function, an optional initial value and a collection.
If an initial value is provided, reduce
applies the function to that
initial value and the first item in the collection. The function is
then applied to that result and the second item in the collection, and
so on. If the collection is empty, the initial value is returned (and
the function is not called).
If an initial value is not provided, and the behavior is a bit more complicated:
- If the collection is empty, the function is called with no arguments and the result is returned,
- If the collection has one element, that element is returned, and the function is not called,
- Otherwise, the function is called with the first two elements of the collection, and then with the result of that call and the third element, and so on.
(reduce + 0 [1 2 3 4 5]) ; (+ 0 1) then (+ 1 2), (+ 3 3), (+ 6 4), (+ 10 5)
;; ⇒ 15
(reduce + 0 []) ; 0 -- + is not called
;; ⇒ 0
(reduce + [1 2 3 4 5]) ; (+ 1 2) then (+ 3 3), (+ 6 4), (+ 10 5)
;; ⇒ 15
(reduce + [1]) ; 1 -- + is not called
;; ⇒ 1
(reduce + []) ; 0 -- (+) is called and produces zero
;; ⇒ 0
reductions
([f coll])
([f val coll])
reductions
takes a function, an optional initial value and a collection.
reductions
returns a lazy sequence of the intermediate values that would
be produced during calls to reduce
with the same arguments.
Like reduce
,
if no initial value is provided, and the collection is empty, the function
is called with no arguments and the result is the only value in the lazy
sequence; if no initial value is provided, and the collection has only one
element, that element is the only value in the lazy sequence, and the
function is not called.
map
([f coll])
([f c1 c2])
([f c1 c2 c3])
([f c1 c2 c3 & colls])
map
takes a function and one or more collections. map
passes an
item from each collection, in order, to the function and returns a
lazy sequence of the results.
The function provided to map
must support an arity matching the
number of collections passed. Due to this, when using more than one
collection, map
stops processing items when any collection runs out of
items.
mapv
([f coll])
([f c1 c2])
([f c1 c2 c3])
([f c1 c2 c3 & colls])
mapv
takes a function and one or more collections. mapv
passes an
item from each collection, in order, to the function and returns a
vector of the results. Unlike map
, mapv
is not lazy.
If mapv
is called with a single collection, it will use a transient vector to build
the result for efficiency.
If mapv
is called with multiple collections, it will first call map
on them
and then turn the result into a vector (using into []
).
The function provided to mapv
must support an arity matching the
number of collections passed. Due to this, when using more than one
collection, mapv
stops processing items when any collection runs out of
items, like map
.
Collection and Sequence Modification
conj
([coll x])
([coll x & xs])
conj
takes a collection and a variable number of arguments.
conj
is short for "conjoin". As the name implies, conj
returns the
collection with those arguments added.
Adding items to a collection occurs at different places depending on the concrete type of collection.
List addition occurs at the beginning of the list. This is because accessing the head of the list is a constant time operation, and accessing the tail requires traversal of the entire list.
(conj '(1 2) 3)
;; ⇒ (3 1 2)
Vectors have constant time access across the entire data structure. `'conj' thusly appends to the end of a vector.
(conj [1 2] 3)
;; ⇒ [1 2 3]
Maps do not have guaranteed ordering, so the location that items are
added is irrelevant. conj
requires vectors of [key value] pairs to
be added to the map.
(conj {:a 1 :b 2 :c 3} [:d 4])
;; ⇒ {:d 4, :a 1, :c 3, :b 2}
(conj {:cats 1 :dogs 2} [:ants 400] [:giraffes 13])
;; ⇒ {:giraffes 13, :ants 400, :cats 1, :dogs 2}
Sets also do not have guaranteed ordering. conj
returns a set with
the item added. As the concept of sets implies, added items will not
duplicate equivalent items if they are present in the set.
(conj #{1 4} 5)
;; ⇒ #{1 4 5}
(conj #{:a :b :c} :b :c :d :e)
;; ⇒ #{:a :c :b :d :e}
empty
([coll])
empty
takes a collection
empty
returns an empty collection of the same type as the collection
provided.
(empty [1 2 3])
;; ⇒ []
(empty {:a 1 :b 2 :c 3})
;; ⇒ {}
assoc
([map key val])
([map key val & kvs])
assoc
takes a key and a value and returns a collection of the same
type as the supplied collection with the key mapped to the new value.
assoc
is similar to get in how it works with maps, records or
vectors. When applied to a map or record, the same type is returned
with the key/value pairs added or modified. When applied to a vector,
a vector is returned with the key acting as an index and the index
being replaced by the value.
Since maps and records can not contain multiple equivalent keys,
supplying assoc
with a key/value that exists in the one will cause
assoc
to return modify the key at that value in the result and not
duplicate the key.
(assoc {:a 1} :b 2)
;; ⇒ {:b 2, :a 1}
(assoc {:a 1 :b 45 :c 3} :b 2)
;; ⇒ {:a 1, :c 3, :b 2}
(defrecord Hand [index middle ring pinky thumb])
(assoc (Hand. 3 4 3.5 2 2) :index 3.75)
;; ⇒ #user.Hand{:index 3.75, :middle 4, :ring 3.5, :pinky 2, :thumb 2}
When using assoc
with a vector, the key is
the index and the value is the value to assign to that index in the
returned vector. The key must be <= (count vector) or a
"IndexOutOfBoundsException" will occur. assoc
can not be used to add
an item to a vector.
(assoc [1 2 76] 2 3) ;= [1 2 3]
;; index 5 does not exist. valid indexes for this vector are: 0, 1, 2
(assoc [1 2 3] 5 6)
;; IndexOutOfBoundsException clojure.lang.PersistentVector.assocN (PersistentVector.java:136)
dissoc
([map])
([map key])
([map key & ks])
dissoc
takes a map and a variable number of keys.
dissoc
returns a map with the supplied keys, and subsequently their
values, removed. Unlike assoc
, dissoc
does not work on
vectors. When a record is provided, dissoc
returns a map. For
similar functionality with vectors, see subvec
and concat
.
(dissoc {:a 1 :b 2 :c 3} :b)
;; ⇒ {:a 1, :c 3}
(dissoc {:a 1 :b 14 :c 390 :d 75 :e 2 :f 51} :b :c :e)
;; ⇒ {:a 1, :f 51, :d 75}
;; note that a map is returned, not a record.
(defrecord Hand [index middle ring pinky thumb])
;; always be careful with the bandsaw!
(dissoc (Hand. 3 4 3.5 2 2) :ring)
;; ⇒ {:index 3, :middle 4, :pinky 2, :thumb 2}
Information about a Collection or Sequence
count
([coll])
count
takes a collection.
Returns a count of the number of items in a collection. An argument of nil returns 0.
(count "Hello")
;; ⇒ 5
(count [1 2 3 4 5 6 7])
;; ⇒ 7
(count nil)
;; ⇒ 0
Note that count does not return in constant time for all
collections. This can be determined with counted?
. Keep in mind
that lazy sequences must be realized to get a count of the items. This
is often not intended and can cause a variety of otherwise cryptic
errors.
(counted? "Hello")
;; ⇒ false
;; will be fully realized when using (count (range 10))
(counted? (range 10))
;; ⇒ false
;; Constant time return of (count)
(counted? [1 2 3 4 5])
;; ⇒ true
empty?
([coll])
empty
takes a collection.
empty?
returns true if the collection has no items, or false if it has 1 or more items.
(empty? [])
;; ⇒ true
(empty? '(1 2 3))
;; ⇒ false
Do not confuse empty?
with empty
. This can be a source of great confusion:
(if (empty [1 2 3]) ;; empty returns an empty seq, which is true! use empty? here.
"It's empty"
"It's not empty")
;; ⇒ "It's empty"
not-empty
([coll])
not-empty
takes a collection.
not-empty
returns nil if the collection has no items. If the collection contains items, the collection is returned.
(not-empty '(:mice :elephants :children))
;; ⇒ (:mice :elephants :children)
(not-empty '())
;; ⇒ nil
Items in a Collection or Sequence
first
([coll])
first
takes a collection.
first
returns the first item in the collection. first
returns nil
if the argument is empty or is nil.
Note that for collections that do not guarantee order like some maps
and sets, the behaviour of first
should not be relied on.
(first (range 10))
;; ⇒ 0
(first [:floor :piano :seagull])
;; ⇒ :floor
(first [])
;; ⇒ nil
rest
([coll])
rest
takes a collection.
rest
returns a seq of items starting with the second element in the
collection. rest
returns an empty seq if the collection only
contains a single item.
rest
should also not be relied on when using maps and sets unless
you are sure ordering is guaranteed.
(rest [13 1 16 -4])
;; ⇒ (1 16 -4)
(rest '(:french-fry))
;; ⇒ '()
The behaviour of rest
should be contrasted with next
. next
returns nil
if the collection only has a single item. This is important when considering "truthiness" of values since an empty seq is still a truthy value but nil
is not.
(if (rest '("stuff"))
(print "Does this print?")) ;; yes, it prints.
;; NEVER FINISHES EXECUTION!
;; "done" is never reached because (rest x) is always a "true" value
(defn inf
[x]
(if (rest x)
(inf (rest x))
"done"))
get
([map key])
([map key not-found])
get
takes an associative collection, a sequence of keys and an optional default value.
get
returns the value for the specified key in a map or record,
index of a vector or value in a set. If the key is not present, get
returns nil or a supplied default value.
;; val of a key in a map
(get {:a 1 :b 2 :c 3} :b)
;; ⇒ 2
;; index of a vector
(get [10 15 20 25] 2)
;; ⇒ 20
;; in a set, returns the value itself if present
(get #{1 10 100 2 20 200} 1)
;; ⇒ 1
;; returns nil if key is not present
(get {:a 1 :b 2} :c)
;; ⇒ nil
;; vector does not have an _index_ of 4. nil is returned
(get [1 2 3 4] 4)
;; ⇒ nil
(defrecord Hand [index middle ring pinky thumb])
(get (Hand. 3 4 3.5 2 2) :index)
;; ⇒ 3
get
also supports a default return value supplied as the last argument.
;; index 4 does not exist. return default value
(get [1 2 3 4] 4 "Not Found")
;; ⇒ "Not Found"
;; key :c does not exist, so return default value of 3
(get {:a 1 :b 2} :c 3)
;; ⇒ 3
contains?
([coll key])
contains?
takes a collection and a key.
contains
returns true if the provided key is present in a
collection. contains
is similar to get
in that vectors treat the
key as an index. contains
will always return false for lists.
(contains? {:a 1 :b 2 :c 3} :c)
;; ⇒ true
;; true if index 2 exists
(contains? ["John" "Mary" "Paul"] 2)
;; ⇒ true
;; false if index 5 does not exist
(contains? ["John" "Mary" "Paul"] 5)
;; ⇒ false
;; "Paul" does not exist as an index
(contains? ["John" "Mary" "Paul"] "Paul")
;; ⇒ false
;; lists are not supported. contains? won't traverse a collection for a result.
(contains? '(1 2 3) 0) ; false in ClojureScript, an exception in Clojure
keys
([map])
keys
takes a map or record.
keys
returns a sequence of the keys in a map or record.
(keys {1 "one" 2 "two" 3 "three"})
;; ⇒ (1 2 3)
(defrecord Hand [index middle ring pinky thumb])
(keys (Hand. 2 4 3 1 2))
;; ⇒ (:index :middle :ring :pinky :thumb)
vals
([map])
vals
takes a map or record.
vals
returns a sequence of vals in a map or record.
(vals {:meows 20 :barks 2 :moos 5})
;; ⇒ (5 2 20)
(defrecord Hand [index middle ring pinky thumb])
(vals (Hand. 1 2 3 4 5))
;; ⇒ (1 2 3 4 5)
take
([n coll])
take
takes a number and a collection.
take
returns a lazy sequence starting with the first value of the
collection and n sequential items after that.
If the number of items in the collection is less than the provided number, the entire collection is returned lazily.
drop
([n coll])
drop
takes a number and a collection.
drop
returns a lazy sequence starting at the nth item of the collection.
take-while
([pred coll])
take-while
takes a function that accepts a single-argument and a
collection.
take-while
returns a lazy sequence of sequential items until the
function returns nil/false value for that item.
(take-while pos? (range 5 -5 -1))
;; => (5 4 3 2 1)
drop-while
([pred coll])
'drop-while` takes a function that accepts a single-argument and a collection.
drop-while
returns a lazy sequence starting at the first item in the
collection that the function returns nil/false.
filter
([pred coll])
filter
takes a function that accepts a single argument and a
collection.
filter
returns a lazy sequence of items for which the
provided predicate produces a truthy value. Contrast to remove
.
(filter even? (range 10))
;; ⇒ (0 2 4 6 8)
(filter #(if (< (count %) 5) %) ["Paul" "Celery" "Computer" "Rudd" "Tayne"])
;; ⇒ ("Paul" "Rudd")
When using sets with filter
, remember that if nil
or false
is in the
set and in the collection, then the predicate will return falsey and the item
will be omitted.
(filter #{:nothing :something nil false} [:nothing :something :things :someone nil false :pigeons])
;; ⇒ (:nothing :something)
filterv
([pred coll])
filterv
takes a function that accepts a single argument and a
collection.
filterv
returns a vector of items for which the
provided predicate produces a truthy value. Contrast to remove
.
(filterv even? (range 10))
;; ⇒ [0 2 4 6 8]
(filterv #(if (< (count %) 5) %) ["Paul" "Celery" "Computer" "Rudd" "Tayne"])
;; ⇒ ["Paul" "Rudd"]
When using sets with filterv
, remember that if nil
or false
is in the
set and in the collection, then the predicate will return falsey and the item
will be omitted.
(filterv #{:nothing :something nil false} [:nothing :something :things :someone nil false :pigeons])
;; ⇒ [:nothing :something]
keep
(keep f coll)
keep
takes a function that accepts a single argument and a
collection.
keep
returns a lazy sequence of non-nil results of the function
applied to each item in the collection in sequence.
;; naive attempt: returns a sequence of true/false
(keep even? (range 10))
;; => (true false true false true false true false true false)
;; return even? item or nil:
(keep #(when (even? %) %) (range 10))
;; => (0 2 4 6 8)
(keep not-empty ["" "Sean" "" "Corfield" ""])
;; => ("Sean" "Corfield")
remove
([pred coll])
remove
takes a function that accepts a single argument and a
collection.
remove
returns a lazy sequence of items that return false
or nil
for the provided predicate. Contrast to filter
.
(remove even? (range 10))
;; ⇒ (1 3 5 7 9)
;; relative complement. probably useless?
(remove {:a 1 :b 2} [:h :k :z :b :s])
;; ⇒ (:h :k :z :s)
When using sets with remove
, remember that if nil or false is in the
set and in the collection, then the predicate will return itself:
nil
. This will cause that item to be included in the returned lazy
sequence.
In this example, when nil and false are tested with the predicate, the predicate returns nil. This is because if the item is present in the set it is returned.
(remove #{:nothing :something nil} [:nothing :something :things :someone nil false :pigeons])
;; ⇒ (:things :someone nil false :pigeons)
some
([pred coll])
some
takes a function that accepts a single argument and a collection.
some
will apply a predicate to each value in a collection until a
non-false/nil result is returned then immediately return that result.
Since collections are "true" values, this makes it possible to return
the first result itself rather than simply true
.
(some even? [1 2 3 4 5])
;; ⇒ true
;; predicate returns the value rather than simply true
(some #(if (even? %) %) [1 2 3 4 5])
;; ⇒ 2
Since maps can be used as functions, you can use a map as a predicate. This will return the value of the first key in the collection that is also in the map.
(some {:a 1 :b 5} [:h :k :d :b])
;; ⇒ 5
Sets can also be used as functions and will return the first item in the collection that is present in the set.
(some #{4} (range 20))
;; ⇒ 4
every?
([pred coll])
every?
takes a function that accepts a single argument and a collection.
every?
returns true if the predicate returns true for every item in
the collection, otherwise it returns false.
(every? even? (range 0 10 2))
;; ⇒ true
;; set can be used to see if collection only contains items in the set.
(every? #{2 3 4} [2 3 4 2 3 4])
;; ⇒ true
Processing Collections and Sequences
partition
([n coll])
([n step coll])
([n step pad coll])
partition
takes a number, an optional step, an optional padding
collection and a collection. If the padding collection is provided, a
step must be provided.
partition
sequentially takes a provided number of items from the
collection in sequence and puts them into lists. This lazy sequence of
lists is returned.
If a step is provided, the lists in the returned lazy sequence start at offsets in the provided collection of that number items in the list.
If a padding collection is provided, the last item in the returned lazy sequence will be padded with the padding collection to achieve the desired partitioning size.
If there is no padding collection provided and there is not enough items to fill the last list in the returned lazy sequence, those items will be not used.
;; divide the sequence into pairs, the value 4 is dropped:
(partition 2 (range 5))
;; => ((0 1) (2 3))
;; staggered pairs can be useful (and the value 4 is included):
(partition 2 1 (range 5))
;; => ((0 1) (1 2) (2 3) (3 4))
;; divide the sequence into pairs and pad the last pair with -1:
(partition 2 2 [-1] (range 5))
;; => ((0 1) (2 3) (4 -1))
partitionv
([n coll])
([n step coll])
([n step pad coll])
partitionv
is just like partition
above, except it returns a
lazy sequence of vectors instead of a lazy sequence of lists.
partition-all
([n coll])
([n step coll])
partition-all
takes a number, an optional step and a collection.
partition-all
sequentially takes a provided number of items from the
collection in sequence and puts them into lists. This lazy sequence of
lists is returned.
If a step is provided, the lists in the returned lazy sequence start at offsets in the provided collection of that number items in the list.
If there are not enough items to fill the last list in the returned lazy sequence, the remaining items will be used in the last list.
;; divide the sequence into pairs, the value 4 is not dropped:
(partition-all 2 (range 5))
;; => ((0 1) (2 3) (4))
partitionv-all
([n coll])
([n step coll])
partitionv-all
is just like partition-all
above, except it returns a
lazy sequence of vectors instead of a lazy sequence of lists.
filter
See: filter
filterv
See: filterv
remove
See: remove
for
See: for
map
See: map
mapv
See: mapv
remove
See: remove
empty?
See: empty
not-empty
See: not-empty
Function Composition and Application
juxt
([])
([f])
([f g])
([f g h])
([f1 f2 f3 & fs])
juxt
takes a variable number of functions.
juxt
returns a function that will return a vector consisting of the
result of applying each of those functions to a provided argument.
;; turn a sequence of database rows into a map from ID to row:
(into {} (map (juxt :id identity)) [{:id 1 :name "Sean"} {:id 2 :name "Jay"}])
comp
([])
([f])
([f g])
([f g h])
([f1 f2 f3 & fs])
comp
takes a variable number of functions.
comp
returns a function that will return the result of applying the
rightmost function to the provided argument, then the second rightmost
function to the result of that etc.
(let [cf (comp f g h)]
(cf x)) ; the same as (f (g (h x)))
fnil
([f x])
([f x y])
([f x y z])
fnil
takes a function and one to three arguments.
fnil
returns a function that replaces any nil`` arguments with the provided values.
fnil` only supports supports patching 3 arguments,
but will pass any arguments beyond that un-patched.
(defn say-info [name location hobby]
(println name "is from" location "and enjoys" hobby))
(def say-info-patched (fnil say-info "Someone" "an unknown location" "Clojure"))
(say-info-patched nil nil nil)
;; ⇒ Someone is from an unknown location and enjoys Clojure
(say-info-patched "Robert" nil "giraffe migrations")
;; ⇒ Robert is from an unknown location and enjoys giraffe migrations
apply
([f args] [f x args] [f x y args] [f x y z args] [f a b c d & args])
apply
takes a variable number of arguments and a collection.
apply
effectively unrolls the supplied args and a collection into a
list of arguments to the supplied function.
(str ["Hel" "lo"])
;; ⇒ "[\"Hel\" \"lo\"]" ;; not what we want, str is operating on the vector
(apply str ["Hel" "lo"]) ;; same as (str "Hel" "lo")
;; ⇒ "Hello"
apply
prepends any supplied arguments to the form as well.
(map + [[1 2 3] [1 2 3]]) ;; This attempts to add 2 vectors with +
;; ClassCastException java.lang.Class.cast (Class.java:2990)
(apply map + [[1 2 3] [1 2 3]]) ;; same as (map + [1 2 3] [1 2 3])
;; ⇒ (2 4 6)
(apply + 1 2 3 [4 5 6]) ;; same as (+ 1 2 3 4 5 6)
;; ⇒ 21
Note that apply can not be used with macros.
->
([x])
([x form])
([x form & more])
->
takes a value and optionally one or more expressions.
->
takes the first argument and inserts it as the second item in the
next form, or creates a list with the first argument as the second
item. The return value of that expression is inserted as the second
item in the next form, making a list if necessary. This continues
until all expressions are evaluated and the final value is returned.
(-> 5
(inc)
(- 3)
(* 2))
;; ⇒ 6
(-> {:a 1 :b 2}
:b
(inc))
;; ⇒ 3
->>
([x])
([x form])
([x form & more])
->>
takes a value and optionally one or more expressions.
->>
takes the first argument and inserts it as the last item in the
next form, or creates a list with the first argument as the last
item. The return value of that expression is inserted as the last item
in the next form, making a list if necessary. This continues until
all expressions are evaluated and the final value is returned.
(->> (range 5) ; (0 1 2 3 4)
(map inc) ; (1 2 3 4 5)
(filter even?) ; (2 4)
(reduce +)) ; (+ 2 4)
;; ⇒ 6
Associative Collections
get-in
([m ks] [m ks not-found])
get-in
takes an associative collection, a sequence of keys and an optional default value.
get-in
takes the first value in the sequence of keys and retrieves
the value, then applies each subsequent key to to the most recently
returned value and returns the final result. If any key is not present
when evaluated then either nil, or a provided default value is
returned.
(get-in {:profile {:personal {:age 28}}} [:profile :personal :age])
;= 28
update-in
([m [k & ks] f & args])
update-in
takes an associative collection, a sequence of keys, a
function and optional arguments to supply to that function.
update-in
takes the first value in the sequence of keys and
retrieves the value, then applies each subsequent key to to the most
recently returned value. The function and optional arguments are
applied to the value and a new nested collection is returned with the
key having the result of that function.
update-in
will create new hash-maps if a key in the sequence of keys
does not exist. The returned collection will have a nested structure
correlating to the provided sequence along with the result of the
function and optional arguments as the value of the final key.
(update-in {:profile {:personal {:age 28}}} [:profile :personal :age] inc)
;= {:profile {:personal {:age 29}}}
assoc-in
([m [k & ks] v])
assoc-in
takes an associative collection, a sequence of keys and a value.
assoc-in
takes the first value in the sequence of keys and retrieves
the value, then applies each subsequent key to to the most recently
returned value. The final key is assigned the provided value and a new
nested collection is returned.
assoc-in
will create new hash-maps if a key in the sequence of keys
does not exist. The returned collection will have a nested structure
correlating to the provided sequence along with the provided value as
the value of the final key.
(assoc-in {:profile {:personal {:age 28}}} [:profile :personal :location] "Vancouver, BC")
;= {:profile {:personal {:location "Vancouver, BC", :age 28}}}
select-keys
([map keyseq])
select-keys
takes an associative collection and a sequence of keys.
select-keys
returns a map containing only the entries that have a
key which is also present in the sequence of keys.
(select-keys {:a 1 :b 2 :c 3} [:a :b])
;= {:b 2, :a 1}
keys
See: keys
vals
See: vals
get
See: get
assoc
See: assoc
dissoc
See: dissoc
Namespace Functions
ns, require, use, import, refer
Please see the Namespace guide
Reference Types
ref, atom, var, agent
Please see the Concurrency and Parallelism Guide
deref, swap!, reset!, dosync, alter, commute, binding
Please see the Concurrency and Parallelism Guide
Contributors
Robert Randolph audiolabs@gmail.com (original author) Michael Klishin michael@defprotocol.org Nguyễn Hà Dương cmpitg@gmail.com