Salta ai contenuti

Clojure Cheat Sheet

Overview

Clojure is a dynamic, general-purpose programming language that combines the approachability of a scripting language with a robust infrastructure for multithreaded programming. As a dialect of Lisp, it features a powerful macro system, but adds immutable persistent data structures, software transactional memory, and first-class functions. Running on the JVM, Clojure provides seamless Java interop while encouraging a fundamentally different approach to state management and program design.

Created by Rich Hickey in 2007, Clojure was designed to be a practical language for professional use. It emphasizes simplicity over complexity, immutability by default, and data-oriented programming. Clojure’s REPL-driven development workflow enables rapid iteration, and its persistent data structures provide efficient immutable collections. The language also targets JavaScript (ClojureScript) and .NET (Clojure CLR), making it truly cross-platform.

Installation

Using the CLI Tools

# macOS
brew install clojure/tools/clojure

# Linux
curl -L -O https://github.com/clojure/brew-install/releases/latest/download/linux-install.sh
chmod +x linux-install.sh
sudo ./linux-install.sh

# Verify
clj --version

Using Leiningen

# macOS
brew install leiningen

# Linux/macOS manual
curl -O https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein
chmod +x lein && sudo mv lein /usr/local/bin/

# Verify
lein version

Start a REPL

# Clojure CLI
clj

# Leiningen
lein repl

# With dependencies
clj -Sdeps '{:deps {cheshire/cheshire {:mvn/version "5.12.0"}}}'

Core Language

Data Types

TypeExampleDescription
Number42, 3.14, 22/7Integers, floats, ratios
String"hello"Java strings
Character\a, \newlineJava characters
Keyword:name, :user/idSelf-evaluating identifiers
Symbolfoo, my-ns/barNames for vars
Booleantrue, falseJava booleans
NilnilNull/nothing
Regex#"pattern"Java regex pattern
List'(1 2 3)Linked list
Vector[1 2 3]Indexed collection
Map{:a 1 :b 2}Key-value pairs
Set#{1 2 3}Unique values

Functions

;; Define a function
(defn greet [name]
  (str "Hello, " name "!"))

;; Multi-arity
(defn greet
  ([] (greet "World"))
  ([name] (str "Hello, " name "!"))
  ([first last] (str "Hello, " first " " last "!")))

;; Variadic
(defn sum [& numbers]
  (reduce + 0 numbers))

;; Anonymous functions
(fn [x] (* x 2))
#(* % 2)          ; shorthand
#(+ %1 %2)        ; multiple args

;; Higher-order functions
(map inc [1 2 3])            ; => (2 3 4)
(filter even? (range 10))    ; => (0 2 4 6 8)
(reduce + [1 2 3 4])         ; => 10
(apply str ["a" "b" "c"])    ; => "abc"

;; Composition
(def process (comp str/upper-case str/trim))
(process "  hello  ") ; => "HELLO"

;; Partial application
(def add5 (partial + 5))
(add5 3) ; => 8

Collections

;; Vectors
(def v [1 2 3 4 5])
(conj v 6)           ; => [1 2 3 4 5 6]
(nth v 2)            ; => 3
(get v 2)            ; => 3
(subvec v 1 3)       ; => [2 3]
(assoc v 0 99)       ; => [99 2 3 4 5]

;; Maps
(def m {:name "Alice" :age 30})
(:name m)            ; => "Alice"
(get m :name)        ; => "Alice"
(assoc m :email "a@b.com")
(dissoc m :age)
(merge m {:role :admin})
(select-keys m [:name])
(update m :age inc)

;; Sets
(def s #{1 2 3})
(conj s 4)           ; => #{1 2 3 4}
(disj s 2)           ; => #{1 3}
(contains? s 2)      ; => true
(clojure.set/union #{1 2} #{2 3})      ; => #{1 2 3}
(clojure.set/intersection #{1 2} #{2 3}) ; => #{2}

;; Sequences (lazy)
(take 5 (range))          ; => (0 1 2 3 4)
(take 5 (iterate inc 0))  ; => (0 1 2 3 4)
(take 5 (repeat :x))      ; => (:x :x :x :x :x)
(take 5 (cycle [1 2 3]))  ; => (1 2 3 1 2)

Destructuring

;; Vector destructuring
(let [[a b & rest] [1 2 3 4 5]]
  {:a a :b b :rest rest})
; => {:a 1 :b 2 :rest (3 4 5)}

;; Map destructuring
(let [{:keys [name age] :or {age 0}} {:name "Alice" :age 30}]
  (str name " is " age))
; => "Alice is 30"

;; Nested destructuring
(let [{:keys [name] {:keys [city]} :address} person]
  (str name " lives in " city))

;; Function parameter destructuring
(defn process-user [{:keys [name email]}]
  (str "User: " name " <" email ">"))

Control Flow

;; if/when
(if (> x 0) "positive" "non-positive")
(when (> x 0) (println "positive") x)

;; cond
(cond
  (< x 0) "negative"
  (= x 0) "zero"
  :else    "positive")

;; case
(case day
  :monday  "Start of week"
  :friday  "Almost weekend"
  "Regular day")

;; Threading macros
(->> (range 10)
     (filter even?)
     (map #(* % %))
     (reduce +))

(-> {:name "Alice"}
    (assoc :role :admin)
    (update :name str/upper-case))

;; some-> (nil-safe threading)
(some-> user :address :city str/upper-case)

Concurrency

;; Atoms (uncoordinated, synchronous)
(def counter (atom 0))
(swap! counter inc)
(reset! counter 0)
@counter ; => 0

;; Refs (coordinated, synchronous via STM)
(def account-a (ref 100))
(def account-b (ref 200))
(dosync
  (alter account-a - 50)
  (alter account-b + 50))

;; Agents (uncoordinated, asynchronous)
(def logger (agent []))
(send logger conj "Event occurred")
@logger ; => ["Event occurred"]

;; Futures and Promises
(def result (future (Thread/sleep 1000) 42))
@result ; => 42 (blocks until ready)

(def p (promise))
(deliver p 42)
@p ; => 42

;; core.async channels
(require '[clojure.core.async :as async])
(let [ch (async/chan 10)]
  (async/go (async/>! ch "hello"))
  (async/go (println (async/<! ch))))

Build Tools

deps.edn (Clojure CLI)

{:paths ["src" "resources"]
 :deps {org.clojure/clojure {:mvn/version "1.11.2"}
        cheshire/cheshire {:mvn/version "5.12.0"}
        ring/ring-core {:mvn/version "1.11.0"}}
 :aliases
 {:dev {:extra-paths ["dev"]
        :extra-deps {nrepl/nrepl {:mvn/version "1.1.0"}}}
  :test {:extra-paths ["test"]
         :extra-deps {lambdaisland/kaocha {:mvn/version "1.87.1366"}}}
  :build {:deps {io.github.clojure/tools.build {:mvn/version "0.9.6"}}
          :ns-default build}}}

project.clj (Leiningen)

(defproject my-app "0.1.0"
  :description "My Clojure application"
  :dependencies [[org.clojure/clojure "1.11.2"]
                 [ring/ring-core "1.11.0"]
                 [compojure "1.7.1"]]
  :main my-app.core
  :profiles {:dev {:dependencies [[nrepl "1.1.0"]]}
             :uberjar {:aot :all}})

Configuration

System Configuration Pattern

;; Using Integrant or Component
(def config
  {:db/pool {:jdbc-url (System/getenv "DATABASE_URL")
             :max-pool-size 10}
   :http/server {:port (Integer/parseInt (or (System/getenv "PORT") "3000"))
                 :handler (ig/ref :app/handler)}})

Advanced Usage

Macros

(defmacro unless [condition & body]
  `(when (not ~condition)
     ~@body))

(defmacro with-timing [label & body]
  `(let [start# (System/nanoTime)
         result# (do ~@body)
         elapsed# (/ (- (System/nanoTime) start#) 1e6)]
     (println (str ~label ": " elapsed# "ms"))
     result#))

(with-timing "Query"
  (fetch-data db query))

Transducers

;; Composable algorithmic transformations
(def xf (comp
          (filter even?)
          (map #(* % 3))
          (take 5)))

(transduce xf + (range 100))
(into [] xf (range 100))
(sequence xf (range 100))

Spec for Validation

(require '[clojure.spec.alpha :as s])

(s/def ::name (s/and string? #(> (count %) 0)))
(s/def ::age (s/and int? #(> % 0)))
(s/def ::email (s/and string? #(re-matches #".+@.+" %)))
(s/def ::user (s/keys :req-un [::name ::age ::email]))

(s/valid? ::user {:name "Alice" :age 30 :email "a@b.com"}) ; => true
(s/explain ::user {:name "" :age -1}) ; prints explanation

Troubleshooting

ProblemSolution
ClassNotFoundExceptionCheck deps; run clj -P to download
NullPointerExceptionUse some?, nil? checks; avoid Java null interop issues
ArityExceptionCheck function argument count; look for missing parens
Slow startupUse clj -J-Dclojure.spec.skip-macros=true; consider GraalVM native
REPL not connectingCheck nREPL port; ensure cider-nrepl middleware is loaded
Stack overflowConvert recursion to loop/recur or trampoline
Memory issuesCheck for head retention in lazy sequences
Reflection warningsAdd type hints: ^String, ^long; use *warn-on-reflection*