Clojure Quick Reference
This quick reference collects the syntax, functions, and commands used daily in Clojure development, organized so you can scan for the right form under pressure — during a coding exercise, a REPL session, or when reading someone else's code. It complements, rather than replaces, the topics on Clojure vs Common Lisp, Clojure Best Practices, and Building a Web App with Ring by pulling the most-referenced primitives from each into one place.
Cricket analogy: This quick reference is like a fielding-positions cheat sheet a captain glances at between overs, a fast, scannable summary rather than the full laws of cricket you'd read cover to cover once.
Core Data Structures and Literals
The four core literal forms are '(1 2 3) or (list 1 2 3) for a list, [1 2 3] for a vector, {:a 1 :b 2} for a map, and #{1 2 3} for a set; nil, true, false, keywords like :keyword, and symbols round out the reader syntax, along with #(...) as shorthand for an anonymous function such as #(+ % 1). Reader macros worth memorizing include ' for quote, ` for syntax-quote, ~ for unquote, ~@ for unquote-splicing, and #_ which discards the next form entirely, handy for commenting out one expression during debugging.
Cricket analogy: The #_ reader macro discarding the next form is like a scorer's eraser for one mistaken entry only, quick and surgical, while ' (quote) is like flagging a hypothetical delivery without it actually counting in the match.
;; Literals
'(1 2 3) ;; list
[1 2 3] ;; vector
{:a 1 :b 2} ;; map
#{1 2 3} ;; set
:keyword ;; keyword
#(+ % 1) ;; anonymous function shorthand
;; Reader macros
`(a ~b ~@c) ;; syntax-quote, unquote, unquote-splicing
#_(println "skip me") ;; discard the next form entirelyEssential Functions by Category
For sequences, the everyday toolkit is map, filter, remove, reduce, reduce-kv, group-by, sort-by, take, drop, partition, and interleave; for maps specifically, assoc, dissoc, update, update-in, get, get-in, merge, and select-keys cover the vast majority of real code. String work leans on clojure.string, aliased str by convention, with functions like str/join, str/split, str/trim, and str/replace, which is worth remembering because these functions are not automatically available — you must :require [clojure.string :as str] explicitly.
Cricket analogy: group-by on a sequence of deliveries, grouping by bowler, is like a stats analyst sorting every ball of an innings by which bowler delivered it, then reduce-kv rolling up each bowler's figures, a two-step pipeline any commentator's stats graphic relies on.
;; Sequences
(map inc [1 2 3]) ;; => (2 3 4)
(filter even? (range 10)) ;; => (0 2 4 6 8)
(reduce + 0 [1 2 3 4]) ;; => 10
(group-by :region orders) ;; => {"west" [...], "east" [...]}
;; Maps
(assoc {:a 1} :b 2) ;; => {:a 1, :b 2}
(update {:a 1} :a inc) ;; => {:a 2}
(update-in {:a {:b 1}} [:a :b] inc) ;; => {:a {:b 2}}
(get-in {:a {:b 1}} [:a :b]) ;; => 1
;; Strings (requires clojure.string)
(require '[clojure.string :as str])
(str/join ", " ["a" "b" "c"]) ;; => "a, b, c"Concurrency Primitives at a Glance
The four state and concurrency primitives to keep straight are atom (swap!/reset!, synchronous, uncoordinated), ref (alter/ref-set inside dosync, synchronous, coordinated via STM), agent (send/send-off, asynchronous, uncoordinated), and future/promise, where future runs a background computation you'll deref later and promise delivers a value exactly once from another thread via deliver. core.async adds a fifth model — channels created with chan and traversed with go blocks using >! and <! — for CSP-style coordination between many lightweight processes.
Cricket analogy: send vs send-off for agents mirrors choosing a designated runner for a quick, in-ground task (send, CPU-bound, fixed pool) versus dispatching someone off the ground entirely to fetch new equipment (send-off, I/O-bound, unbounded pool), using the wrong one for the wrong errand clogs the rotation.
Quick disambiguation: use send for CPU-bound agent actions, backed by a fixed thread pool, and send-off for actions that block on I/O, backed by an unbounded or cached thread pool. Mixing them up can starve the fixed pool used for compute-bound agent work across your whole application.
Project Tooling and REPL Commands
Project tooling centers on two systems: Leiningen (lein repl, lein test, lein uberjar, configured via project.clj) and the newer official tools.deps/Clojure CLI (clj or clojure, configured via deps.edn, with clj -X:test or clj -T:build for task running). At the REPL itself, (doc name) prints a function's docstring, (source name) prints its source, (find-doc "regex") searches all docstrings, and require with :reload, or a proper reloaded-workflow tool, reloads changed namespaces without restarting the process.
Cricket analogy: (doc function-name) instantly printing documentation is like a coach glancing at a player's stat card mid-match instead of digging through a season-long archive, quick, in-context lookup exactly when you need it.
(require 'my.ns :reload) only reloads that one namespace, not its dependents. If you change a function that other already-loaded namespaces reference, use :reload-all or a proper reloaded-workflow tool such as clojure.tools.namespace.repl/refresh so downstream namespaces pick up the change too.
- Core literals: '() or (list) for lists, [] for vectors, {} for maps, #{} for sets, plus #(...) for anonymous functions.
- Reader macros to know: ' (quote), ` (syntax-quote), ~ (unquote), ~@ (unquote-splicing), #_ (discard next form).
- Everyday sequence toolkit: map, filter, reduce, group-by, sort-by; everyday map toolkit: assoc, update, update-in, get-in, merge.
- clojure.string functions (str/join, str/split, and so on) require an explicit :require, they are not in clojure.core.
- Four state primitives: atom (sync, uncoordinated), ref (sync, coordinated via dosync), agent (async, uncoordinated), future/promise (one-off background/deferred values).
- Use send for CPU-bound agent work and send-off for I/O-bound agent work to avoid starving the fixed thread pool.
- Leiningen (project.clj) and the Clojure CLI/tools.deps (deps.edn) are the two dominant build tools; (doc), (source), and (find-doc) are the core REPL lookup commands.
Practice what you learned
1. Which reader macro discards the very next form entirely, without evaluating it?
2. Which namespace must be explicitly required to use functions like str/join and str/split?
3. Which agent-dispatch function should be used for actions that block on I/O, such as an HTTP call?
4. Which function updates a nested value inside a map by applying a function to it, given a path of keys?
5. At the REPL, what does (doc some-fn) do?
Was this page helpful?
You May Also Like
Clojure Best Practices
A practical guide to writing idiomatic Clojure: function and namespace design, choosing the right state primitive, structured error handling, and readable threading pipelines.
Building a Web App with Ring
How to build a Clojure web application on Ring: the handler/middleware contract, request and response maps, routing with Reitit or Compojure, and running a Jetty server.
Clojure Interview Questions
What Clojure interviews actually probe — core language fundamentals, concurrency reasoning, common live-coding patterns, and tooling/JVM interop knowledge — with the reasoning behind common answers.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics