Browse Learn Clojure Foundations as a Java Developer

Evaluate Forms in the REPL

Use the Clojure REPL to evaluate complete forms, inspect return values, require helper namespaces, work with recent results, and avoid confusing scratch state with saved source.

The basic REPL skill is not typing commands. It is evaluating the right form and reading the returned value accurately.

Evaluate Complete Forms

Clojure code is built from forms. The REPL reads a complete form, evaluates it, prints the value, and waits for the next form.

1(+ 10 20 30)
2;; => 60
3
4(filter even? [1 2 3 4 5 6])
5;; => (2 4 6)
6
7(assoc {:id 1001 :status :new} :status :paid)
8;; => {:id 1001, :status :paid}

This changes the learning loop for Java engineers:

Java-style question REPL-style question
Did the whole app run? What value did this form return?
What log line should I add? What expression exposes the value I need?
Which class owns this method? Which namespace holds this function?
Do I need a full debugger session? Can I evaluate the function directly?

Build Data First

Because Clojure data is literal and printable, use data directly:

1(def sample-order
2  {:order/id 1001
3   :order/lines [{:sku "A1" :qty 2 :price 10}
4                 {:sku "B2" :qty 1 :price 25}]})
5
6(map :qty (:order/lines sample-order))
7;; => (2 1)

This is often faster than creating Java fixture objects just to ask a simple question.

Define and Call Small Functions

1(defn line-total [line]
2  (* (:qty line) (:price line)))
3
4(defn order-total [order]
5  (reduce + (map line-total (:order/lines order))))
6
7(order-total sample-order)
8;; => 45

Once the function is useful, move it to a source file and evaluate it from there. Do not let important behavior live only in your terminal history.

Require Namespaces Deliberately

Load standard libraries with require:

1(require '[clojure.string :as str])
2
3(str/split "sku-qty-price" #"-")
4;; => ["sku" "qty" "price"]

Use aliases consistently. They make REPL forms closer to real source code and prevent copy/paste drift.

Use Inspection Helpers

In many standard REPL sessions, helpers such as doc, source, apropos, and pst are available in user. If not, require them:

1(require '[clojure.repl :refer [doc source apropos pst]])
2
3(doc reduce)
4(apropos "partition")

For Java developers, this is like having API documentation and source lookup inside the running process.

Use Recent Result Vars

1(range 10)
2;; => (0 1 2 3 4 5 6 7 8 9)
3
4(take 3 *1)
5;; => (0 1 2)
Var Meaning
*1 Most recent result
*2 Previous result
*3 Result before that
*e Most recent exception

Use these for short investigations. Avoid building long, invisible chains that nobody else can reproduce.

Know When to Save

Move code from REPL to source when:

  • the function explains a domain idea
  • the same expression is evaluated more than twice
  • the sample data is useful as a test fixture
  • another developer should be able to reproduce it
  • you need Git history or review

Common Mistakes

Mistake Why it hurts
Evaluating fragments instead of complete forms The REPL waits or errors in confusing ways
Leaving important defs only in the session Restart loses the work
Copying REPL-only aliases into source without checking namespace forms Source fails to load
Printing everything You miss Clojure’s value-oriented inspection style
Forgetting the current namespace Vars end up in the wrong place

Key Takeaways

  • Evaluate complete forms and inspect return values.
  • Use Clojure literals to build realistic sample data quickly.
  • Move durable functions from REPL into source files.
  • Require namespaces with aliases that match source conventions.
  • Use *1, *2, *3, and *e for short investigations, not hidden workflows.

Quiz: Evaluate Forms

### What is the REPL's basic unit of evaluation? - [x] A complete Clojure form - [ ] A Java class file - [ ] A Git diff - [ ] A single terminal screen > **Explanation:** The REPL reads and evaluates complete Clojure forms. ### Why should useful REPL functions move into source files? - [x] Source files are durable, reviewable, and reproducible. - [ ] The REPL cannot define functions. - [ ] Clojure ignores source files. - [ ] Functions only work after packaging. > **Explanation:** REPL state is temporary; source files preserve the program. ### What does `*e` hold? - [x] The most recent exception - [ ] The current namespace - [ ] The current editor file - [ ] The first result in the session > **Explanation:** `*e` stores the latest exception in the REPL.
Revised on Saturday, May 23, 2026