Clojure

Programming at the REPL

Introduction

  • What is the Clojure REPL?

tangible

For launching and operating a local development environment, e.g a local web server For debugging For getting familiar with a Clojure codebase - including the Clojure language itself! For exploration, e.g R-style exploratory data analysis

  • Clojure developers typically use the REPL a lot when developing

  • Interactive development: modifying a program when running instead a re-compiling and running

Launching a basic Clojure REPL

Use any of the following methods to start a basic Clojure REPL in a terminal window:

Using the CLI tools

The easiest way to start a Clojure REPL is with using the clj command of the Clojure CLI tools:

clj ## run this command in a terminal window

You should see an output like the following:

Clojure 1.9.0
user=>

See Getting Started to learn how to install the Clojure CLI.

You can exit the REPL by typing Ctrl+D (pressing the Ctrl and D keys at the same time).

Using a project management tool

Leiningen

If you have installed Leiningen, you can use it to launch a REPL:

lein repl

You should see an output like the following:

nREPL server started on port 64411 on host 127.0.0.1 - nrepl://127.0.0.1:64411
REPL-y 0.3.7, nREPL 0.2.12
Clojure 1.8.0
Java HotSpot(TM) 64-Bit Server VM 1.8.0_05-b13
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

user=>

If you run lein repl from inside a Leiningen project directory, the library dependencies and source code of the project will be available at the REPL.

Boot

If you have installed Boot, you can use it to launch a REPL:

boot repl

You should see an output like the following:

nREPL server started on port 50109 on host 127.0.0.1 - nrepl://127.0.0.1:50109
REPL-y 0.3.7, nREPL 0.2.12
Clojure 1.9.0
Java HotSpot(TM) 64-Bit Server VM 1.8.0_05-b13
        Exit: Control+D or (exit) or (quit)
    Commands: (user/help)
        Docs: (doc function-name-here)
              (find-doc "part-of-name-here")
Find by Name: (find-name "part-of-name-here")
      Source: (source function-name-here)
     Javadoc: (javadoc java-object-or-class-here)
    Examples from clojuredocs.org: [clojuredocs or cdoc]
              (user/clojuredocs name-here)
              (user/clojuredocs "ns-here" "name-here")
boot.user=>

Using Java and the Clojure JAR

If you have downloaded and built Clojure, you can use Java to launch a Clojure REPL:

java -jar clojure.jar

You should see an output like the following:

Clojure 1.9.0
user=>

Basic usage

Evaluating Clojure expressions

Now, you can evaluate Clojure expressions by simply typing them into the REPL and pressing ENTER:

user=> (+ 2 3)
5
user=> (defn factorial [n]
(if (= n 0)
  1
  (* n (factorial (dec n)))))
#'user/factorial
user=> (factorial 10)
3628800
user=>

Under each expression, we see the result of evaluating the expression. This is what a REPL does: for each expression that we submit to it, the REPL Reads it, Evaluates it, then Prints the result, all of this in a Loop.

If you are in the process of learning Clojure, take some time to experiment at the REPL. The rapid feedback loop it provides makes for a very effective learning environment.

Although the above examples are very basic, you can run full-featured Clojure programs in this way. Clojure was designed so that its REPL environment provides the full power of the language: you could actually run any existing Clojure program simply by pasting the content of the source files in the right order into the REPL.

Tip: using an editor next to your REPL

Editing Clojure code inside the terminal window can get tedious; when that is the case, one simple trick is to write the code in a text editor of your choosing that has a syntax-aware Clojure mode, and copy and paste code from the editor to the REPL terminal window. Here’s an example of what this looks like (the editor used is Atom):

Editor next to CLI REPL

Seasoned Clojure programmers typically use a much more advanced setup for their REPL (tight editor integration, ergonomic REPL clients, etc.). Such tools can provide a very significant productivity boost, and we will mention them later in this guide.

Nevertheless, starting with a 'raw' setup like the above is enough for the scope of this guide, and can be beneficial later to understand how the more advanced tools work behind the scenes.

The 2 flavors of printing

Consider the following evaluation:

user=> (println "Hello World")
Hello World
nil

This is strange: unlike the previous examples, it looks like evaluating the (println "Hello World") expression yielded 2 results: Hello World and nil.

This is because the println function prints its argument to the standard output but returns nil. Therefore, the 2 lines we see under our expression are very different in nature:

  • Hello World is a side effect of evaluating the expression (printing to standard output)

  • nil is the result of evaluating the expression

Calling Clojure libs from the REPL

So far, we have only called code that we had defined manually at the REPL (for instance our factorial function defined above). But the REPL also lets you use pre-existing Clojure code, i.e Clojure libs.[1] Given a Clojure lib with namespace my.name.space, you can use (require '[my.name.space]) to make that lib’s code loaded and available in the REPL.

For example, clojure.string is a lib bundled with Clojure for manipulating text. Let’s require clojure.string and call its clojure.string/upper-case function:

user=> (require '[clojure.string])
nil
user=> (clojure.string/upper-case "clojure")
"CLOJURE"

require also lets use define an alias for the clojure.string namespace, by adding an :as clause. This enables us to refer to names defined in the clojure.string namespace more concisely:

user=> (require '[clojure.string :as str])
nil
user=> (str/upper-case "clojure")
"CLOJURE"

Finally, if we’re very lazy and don’t want to type an alias at all, we can add a :refer clause:

user=> (require '[clojure.string :refer [upper-case]])
nil
user=> (upper-case "clojure")
"CLOJURE"

Looking up documentation

The REPL can also be used for looking up API documentation, using the clojure.repl lib. Evaluate the following expression at the REPL:

user=> (require '[clojure.repl :refer :all])
nil

This expression makes all the names defined in the clojure.repl namespace available in the REPL.

You can print the API documentation of a given Var by calling doc on the name of that Var:

user=> (doc nil?)
-------------------------
clojure.core/nil?
([x])
  Returns true if x is nil, false otherwise.
nil
user=> (doc clojure.string/upper-case)
-------------------------
clojure.string/upper-case
([s])
  Converts string to all upper-case.
nil

You can also view the source code that was used to define a Var using source:

user=> (source some?)
(defn some?
  "Returns true if x is not nil, false otherwise."
  {:tag Boolean
   :added "1.6"
   :static true}
  [x] (not (nil? x)))
nil

You can use dir to list the names of all the Vars defined a given namespace. Let’s do this with the clojure.string namespace:

user=> (dir clojure.string)
blank?
capitalize
ends-with?
escape
includes?
index-of
join
last-index-of
lower-case
re-quote-replacement
replace
replace-first
reverse
split
split-lines
starts-with?
trim
trim-newline
triml
trimr
upper-case
nil

As another example, let’s use dir to see what’s available in clojure.repl itself:

user=> (dir clojure.repl)
apropos
demunge
dir
dir-fn
doc
find-doc
pst
root-cause
set-break-handler!
source
source-fn
stack-element-str
thread-stopper
nil

We recognize the doc, source and dir operations we’ve used so far.

If you don’t exactly remember the name of some Var, you can search for it using apropos:

user=> (apropos "index")
(clojure.core/indexed? clojure.core/keep-indexed clojure.core/map-indexed clojure.string/index-of clojure.string/last-index-of)

apropos only searches Var names; you can search docstrings (the text that is printed by doc) using find-doc:

user=> (find-doc "indexed")
-------------------------
clojure.core/contains?
([coll key])
 Returns true if key is present in the given collection, otherwise
 returns false.  Note that for numerically indexed collections like
 vectors and Java arrays, this tests if the numeric key is within the
 range of indexes. 'contains?' operates constant or logarithmic time;
 it will not perform a linear search for a value.  See also 'some'.
-------------------------
clojure.core/indexed?
([coll])
 Return true if coll implements Indexed, indicating efficient lookup by index
-------------------------
clojure.core/keep-indexed
([f] [f coll])
 Returns a lazy sequence of the non-nil results of (f index item). Note,
 this means false return values will be included.  f must be free of
 side-effects.  Returns a stateful transducer when no collection is
 provided.
-------------------------
clojure.core/map-indexed
([f] [f coll])
 Returns a lazy sequence consisting of the result of applying f to 0
 and the first item of coll, followed by applying f to 1 and the second
 item in coll, etc, until coll is exhausted. Thus function f should
 accept 2 arguments, index and item. Returns a stateful transducer when
 no collection is provided.
nil

Documentation is available only for libs that have been required.

For instance, if you have not required the clojure.set namespace, you won’t be able to search documentation for clojure.set/union. This is illustrated by this example REPL session:

clj
Clojure 1.9.0
user=> (doc clojure.set/union)
nil                             ;; no doc found
user=> (apropos "union")
()
user=> (require '[clojure.set]) ;; now we're requiring clojure.set
nil
user=> (doc clojure.set/union)
-------------------------
clojure.set/union
([] [s1] [s1 s2] [s1 s2 & sets])
  Return a set that is the union of the input sets
nil
user=> (apropos "union")
(clojure.set/union)
user=>

Data visualization at the REPL

Each time we evaluate an expression, the REPL shows us a textual representation of the result: that’s the Print part of Read-Eval-Print-Loop. Most of the times, this textual representation is clear enough for the programmer, but sometimes it becomes difficult to read - especially when dealing with big or deeply nested data structures.

Fortunately, the REPL provides sharper tools for data visualization.

Pretty-printing using clojure.pprint

As an example, consider the following code, which computes a summary of the arithmetic properties of some numbers:

user=> (defn number-summary
  "Computes a summary of the arithmetic properties of a number, as a data structure."
  [n]
  (let [proper-divisors (into (sorted-set)
                          (filter
                            (fn [d]
                              (zero? (rem n d)))
                            (range 1 n)))
        divisors-sum (apply + proper-divisors)]
    {:n n
     :proper-divisors proper-divisors
     :even? (even? n)
     :prime? (= proper-divisors #{1})
     :perfect-number? (= divisors-sum n)}))
#'user/number-summary
user=> (mapv number-summary [5 6 7 12 28 42])
[{:n 5, :proper-divisors #{1}, :even? false, :prime? true, :perfect-number? false} {:n 6, :proper-divisors #{1 2 3}, :even? true, :prime? false, :perfect-number? true} {:n 7, :proper-divisors #{1}, :even? false, :prime? true, :perfect-number? false} {:n 12, :proper-divisors #{1 2 3 4 6}, :even? true, :prime? false, :perfect-number? false} {:n 28, :proper-divisors #{1 2 4 7 14}, :even? true, :prime? false, :perfect-number? true} {:n 42, :proper-divisors #{1 2 3 6 7 14 21}, :even? true, :prime? false, :perfect-number? false}]
user=>

For now, you don’t need to understand the code of the number-summary function defined above: we’re just using it as a pretext to generate some bulky data structures. Real-world Clojure programming for a specific domain will provide you with many examples of such bulky data structures.

As we can see, the result of our last expression is condensed on a single line, which makes it hard to read:

user=> (mapv number-summary [5 6 7 12 28 42])
[{:n 5, :proper-divisors #{1}, :even? false, :prime? true, :perfect-number? false} {:n 6, :proper-divisors #{1 2 3}, :even? true, :prime? false, :perfect-number? true} {:n 7, :proper-divisors #{1}, :even? false, :prime? true, :perfect-number? false} {:n 12, :proper-divisors #{1 2 3 4 6}, :even? true, :prime? false, :perfect-number? false} {:n 28, :proper-divisors #{1 2 4 7 14}, :even? true, :prime? false, :perfect-number? true} {:n 42, :proper-divisors #{1 2 3 6 7 14 21}, :even? true, :prime? false, :perfect-number? false}]

We can use the clojure.pprint lib to print the result in a more 'visual' format:

user=> (require '[clojure.pprint :as pp])
nil
user=> (pp/pprint (mapv number-summary [5 6 7 12 28 42]))
[{:n 5,
  :proper-divisors #{1},
  :even? false,
  :prime? true,
  :perfect-number? false}
 {:n 6,
  :proper-divisors #{1 2 3},
  :even? true,
  :prime? false,
  :perfect-number? true}
 {:n 7,
  :proper-divisors #{1},
  :even? false,
  :prime? true,
  :perfect-number? false}
 {:n 12,
  :proper-divisors #{1 2 3 4 6},
  :even? true,
  :prime? false,
  :perfect-number? false}
 {:n 28,
  :proper-divisors #{1 2 4 7 14},
  :even? true,
  :prime? false,
  :perfect-number? true}
 {:n 42,
  :proper-divisors #{1 2 3 6 7 14 21},
  :even? true,
  :prime? false,
  :perfect-number? false}]
nil

Tip: Using an editor for syntax-highlighting the results

If you want your pretty-printed result to be displayed with more visual contrast, you can also copy it to your editor buffer (the editor used below is Emacs):

Copying pretty-printed result to editor

Needing to pretty-print the last REPL result is so common that clojure.pprint has a function for that: clojure.pprint/pp

user=> (mapv number-summary [12 28])
[{:n 12, :proper-divisors #{1 2 3 4 6}, :even? true, :prime? false, :perfect-number? false} {:n 28, :proper-divisors #{1 2 4 7 14}, :even? true, :prime? false, :perfect-number? true}]
user=> (pp/pp)
[{:n 12,
  :proper-divisors #{1 2 3 4 6},
  :even? true,
  :prime? false,
  :perfect-number? false}
 {:n 28,
  :proper-divisors #{1 2 4 7 14},
  :even? true,
  :prime? false,
  :perfect-number? true}]
nil

Finally, for a result which is a sequence of maps (like the above), you can use clojure.pprint/print-table to print it as a table:

user=> (pp/print-table (mapv number-summary [6 12 28]))

| :n | :proper-divisors | :even? | :prime? | :perfect-number? |
|----+------------------+--------+---------+------------------|
|  6 |         #{1 2 3} |   true |   false |             true |
| 12 |     #{1 2 3 4 6} |   true |   false |            false |
| 28 |    #{1 2 4 7 14} |   true |   false |             true |
nil

Accessing recent results: *1, *2, *3

In the REPL, the last evaluated result can be retrieved by evaluating *1; the one before that is saved in *2, and the one before that in *3:

user=> (mapv number-summary [6 12 28])
[{:n 6, :proper-divisors #{1 2 3}, :even? true, :prime? false, :perfect-number? true} {:n 12, :proper-divisors #{1 2 3 4 6}, :even? true, :prime? false, :perfect-number? false} {:n 28, :proper-divisors #{1 2 4 7 14}, :even? true, :prime? false, :perfect-number? true}]
user=> (pp/pprint *1) ;; using *1 instead of re-typing the pevious expression (or its result)
[{:n 6,
 :proper-divisors #{1 2 3},
 :even? true,
 :prime? false,
 :perfect-number? true}
{:n 12,
 :proper-divisors #{1 2 3 4 6},
 :even? true,
 :prime? false,
 :perfect-number? false}
{:n 28,
 :proper-divisors #{1 2 4 7 14},
 :even? true,
 :prime? false,
 :perfect-number? true}]
nil
user=> *1 ;; now *1 has changed to become nil (because pp/pprint returns nil)
nil
user=> *3 ;; ... which now means that our initial result is in *3:
[{:n 6, :proper-divisors #{1 2 3}, :even? true, :prime? false, :perfect-number? true} {:n 12, :proper-divisors #{1 2 3 4 6}, :even? true, :prime? false, :perfect-number? false} {:n 28, :proper-divisors #{1 2 4 7 14}, :even? true, :prime? false, :perfect-number? true}]
user=>

Tip: saving a result by def-ining it

If you want to keep a result around for longer than 3 evaluations, you can simply evaluate (def <some-name> *1):

user=> (mapv number-summary [6 12 28])
[{:n 6, :proper-divisors #{1 2 3}, :even? true, :prime? false ; ...
user=> (def my-summarized-numbers *1) ;; saving the result
#'user/my-summarized-numbers
user=> my-summarized-numbers
[{:n 6, :proper-divisors #{1 2 3}, :even? true, :prime? false ; ...
user=> (count my-summarized-numbers)
3
user=> (first my-summarized-numbers)
{:n 6, :proper-divisors #{1 2 3}, :even? true, :prime? false, ; ...
user=> (pp/print-table my-summarized-numbers)

| :n | :proper-divisors | :even? | :prime? | :perfect-number? |
|----+------------------+--------+---------+------------------|
|  6 |         #{1 2 3} |   true |   false |             true |
| 12 |     #{1 2 3 4 6} |   true |   false |            false |
| 28 |    #{1 2 4 7 14} |   true |   false |             true |
nil
user=>

Investigating Exceptions

Some expressions won’t return a result when you evaluate them, but throw an Exception instead. Throwing an Exception is your program saying to you: "something went wrong when evaluating the expression, and I don’t know how to deal with that."

For instance, an Exception will be thrown if you divide a number by zero:

user=> (/ 1 0)
ArithmeticException Divide by zero  clojure.lang.Numbers.divide (Numbers.java:163)

By default, the REPL prints a one-line summary of the Exception: its type, its message, and the source code location where the Exception was thrown:

ArithmeticException Divide by zero  clojure.lang.Numbers.divide (Numbers.java:163)
^------type-------- ^--message----  ^location where the Exception was thrown

This can be enough in many cases, but there is more information available.

First, you can visualize the the stacktrace of the Exception - that is, the chain of function calls which led to the faulty instruction. The stacktrace can be printed using clojure.repl/pst:

user=> (pst *e)
ArithmeticException Divide by zero
	clojure.lang.Numbers.divide (Numbers.java:163)
	clojure.lang.Numbers.divide (Numbers.java:3833)
	user/eval15 (NO_SOURCE_FILE:3)
	user/eval15 (NO_SOURCE_FILE:3)
	clojure.lang.Compiler.eval (Compiler.java:7062)
	clojure.lang.Compiler.eval (Compiler.java:7025)
	clojure.core/eval (core.clj:3206)
	clojure.core/eval (core.clj:3202)
	clojure.main/repl/read-eval-print--8572/fn--8575 (main.clj:243)
	clojure.main/repl/read-eval-print--8572 (main.clj:243)
	clojure.main/repl/fn--8581 (main.clj:261)
	clojure.main/repl (main.clj:261)
nil

Tip: the last thrown Exception can be obtained by evaluating *e.

Finally, just evaluating the Exception at the REPL can provide a useful visualization:

user=> *e
#error {
 :cause "Divide by zero"
 :via
 [{:type java.lang.ArithmeticException
   :message "Divide by zero"
   :at [clojure.lang.Numbers divide "Numbers.java" 163]}]
 :trace
 [[clojure.lang.Numbers divide "Numbers.java" 163]
  [clojure.lang.Numbers divide "Numbers.java" 3833]
  [user$eval15 invokeStatic "NO_SOURCE_FILE" 3]
  [user$eval15 invoke "NO_SOURCE_FILE" 3]
  [clojure.lang.Compiler eval "Compiler.java" 7062]
  [clojure.lang.Compiler eval "Compiler.java" 7025]
  [clojure.core$eval invokeStatic "core.clj" 3206]
  [clojure.core$eval invoke "core.clj" 3202]
  [clojure.main$repl$read_eval_print__8572$fn__8575 invoke "main.clj" 243]
  [clojure.main$repl$read_eval_print__8572 invoke "main.clj" 243]
  [clojure.main$repl$fn__8581 invoke "main.clj" 261]
  [clojure.main$repl invokeStatic "main.clj" 261]
  [clojure.main$repl_opt invokeStatic "main.clj" 325]
  [clojure.main$main invokeStatic "main.clj" 424]
  [clojure.main$main doInvoke "main.clj" 387]
  [clojure.lang.RestFn invoke "RestFn.java" 397]
  [clojure.lang.AFn applyToHelper "AFn.java" 152]
  [clojure.lang.RestFn applyTo "RestFn.java" 132]
  [clojure.lang.Var applyTo "Var.java" 702]
  [clojure.main main "main.java" 37]]}

In this simplistic example, displaying all this information may be more than what is needed to diagnose the issue; but this visualization becomes more helpful for 'real-world' Exceptions, which tend to have the following charateristics in Clojure programs:

  • Exceptions convey data: in Clojure programs, it’s common to attach additional data to an Exception (not just a human-readable error message): this is done by creating the Exception via clojure.core/ex-info.

  • Exceptions are chained: an Exception can be annotated with an optional cause, which is another (lower-level) Exception.

Here’s an example program which demonstrates these sort of Exceptions.

(defn divide-verbose
  "Divides two numbers `x` and `y`, but throws more informative Exceptions when it goes wrong.
  Returns a (double-precision) floating-point number."
  [x y]
  (try
    (double (/ x y))
    (catch Throwable cause
      (throw
        (ex-info
          (str "Failed to divide " (pr-str x) " by " (pr-str y))
          {:numerator x
           :denominator y}
          cause)))))

(defn average
  "Computes the average of a collection of numbers."
  [numbers]
  (try
    (let [sum (apply + numbers)
          cardinality (count numbers)]
      (divide-verbose sum cardinality))
    (catch Throwable cause
      (throw
        (ex-info
          "Failed to compute the average of numbers"
          {:numbers numbers}
          cause)))))

We don’t know it yet, but our average function fails when applied to an empty collection of numbers. However, visualizing the Exception makes it easy to diagnose:

user=> (average [])
ArithmeticException Divide by zero  clojure.lang.Numbers.divide (Numbers.java:163)
user=> *e  ;; notice the `:data` key inside the chain of Exceptions represented in `:via`
#error {
 :cause "Divide by zero"
 :via
 [{:type clojure.lang.ExceptionInfo
   :message "Failed to compute the average of numbers"
   :data {:numbers []}
   :at [clojure.core$ex_info invokeStatic "core.clj" 4739]}
  {:type clojure.lang.ExceptionInfo
   :message "Failed to divide 0 by 0"
   :data {:numerator 0, :denominator 0}
   :at [clojure.core$ex_info invokeStatic "core.clj" 4739]}
  {:type java.lang.ArithmeticException
   :message "Divide by zero"
   :at [clojure.lang.Numbers divide "Numbers.java" 163]}]
 :trace
 [[clojure.lang.Numbers divide "Numbers.java" 163]
  [user$divide_verbose invokeStatic "NO_SOURCE_FILE" 11]
  [user$divide_verbose invoke "NO_SOURCE_FILE" 6]
  [user$average invokeStatic "NO_SOURCE_FILE" 25]
  [user$average invoke "NO_SOURCE_FILE" 19]
  [user$eval155 invokeStatic "NO_SOURCE_FILE" 32]
  [user$eval155 invoke "NO_SOURCE_FILE" 32]
  [clojure.lang.Compiler eval "Compiler.java" 7062]
  [clojure.lang.Compiler eval "Compiler.java" 7025]
  [clojure.core$eval invokeStatic "core.clj" 3206]
  [clojure.core$eval invoke "core.clj" 3202]
  [clojure.main$repl$read_eval_print__8572$fn__8575 invoke "main.clj" 243]
  [clojure.main$repl$read_eval_print__8572 invoke "main.clj" 243]
  [clojure.main$repl$fn__8581 invoke "main.clj" 261]
  [clojure.main$repl invokeStatic "main.clj" 261]
  [clojure.main$repl_opt invokeStatic "main.clj" 325]
  [clojure.main$main invokeStatic "main.clj" 424]
  [clojure.main$main doInvoke "main.clj" 387]
  [clojure.lang.RestFn invoke "RestFn.java" 397]
  [clojure.lang.AFn applyToHelper "AFn.java" 152]
  [clojure.lang.RestFn applyTo "RestFn.java" 132]
  [clojure.lang.Var applyTo "Var.java" 702]
  [clojure.main main "main.java" 37]]}

Graphical and web-based visualizations

Finally, the REPL being a full-featured programming environment, it is not limited to text-based visualizations. Here are some handy "graphical" visualization tools bundled Clojure:

clojure.java.javadoc lets you view the Javadoc of a class or object. Here is how to view the Javadoc for a Java regex Pattern:

user=> (require '[clojure.java.javadoc :as jdoc])
nil
user=> (jdoc/javadoc #"a+")
true
user=> (jdoc/javadoc java.util.regex.Pattern) ;; equivalent to the above
true

clojure.inspector lets you open GUI-based visualizations of data, for instance:

user=> (require '[clojure.inspector :as insp])
nil
user=> (insp/inspect-table (mapv number-summary [2 5 6 28 42]))
#object[javax.swing.JFrame 0x26425897 "javax.swing.JFrame[frame1,0,23,400x600,layout=java.awt.BorderLayout,title=Clojure Inspector,resizable,normal,defaultCloseOperation=HIDE_ON_CLOSE,rootPane=javax.swing.JRootPane[,0,22,400x578,layout=javax.swing.JRootPane$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=16777673,maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabled=true]"]

clojure.inspector table viz

Finally, clojure.java.browse/browse-url lets you open any URL in a Web browser, which can be handy for specific needs.

Navigating namespaces

So far we have only used the REPL for small self-contained experiments; but the REPL is most valuable for putting yourself in the shoes of the program you are developing or debugging, i.e evaluating exactly the same expressions in the REPL as your program does when it runs.

This is achieved by giving your REPL the same context as your running program, which implies using REPL in the same namespaces where your code is defined. We will see how to do that in the following sections.

Namespaces are one of the trickiest part of Clojure. If you’re just learning the language, feel free to skip this part for now; you can come back to it when you start working on 'real-world' Clojure projects.

The current namespace

When you evaluate code in the REPL, you are always evaluating code in the context of the current namespace.

The current namespace determines:

  • How the code that you are writing may refer to code from other namespaces.

For example, if the current namespace is myapp.foo.bar and you evaluate (require [clojure.set :as cset :refer [union]]), you can now refer to the clojure.set/union Var either by cset/union (because of the :as cset alias) or just union (because of :refer [union]):

$ clj
Clojure 1.9.0
user=> *ns*
#object[clojure.lang.Namespace 0x7d1cfb8b "user"]
user=> (ns myapp.foo.bar) ;; creating and switching to the myapp.foo.bar namespace - `ns` will be explained later in this guide.
nil
myapp.foo.bar=> (require '[clojure.set :as cset :refer [union]]) ;; this will only affect the current namespace
nil
myapp.foo.bar=> (cset/union #{1 2} #{2 3})
#{1 3 2}
myapp.foo.bar=> (union #{1 2} #{2 3})
#{1 3 2}
myapp.foo.bar=> (cset/intersection #{1 2} #{2 3})
#{2}
myapp.foo.bar=> (in-ns 'user) ;; now switching back to the `user` namespace - `in-ns` will be explained later in this guide.
#object[clojure.lang.Namespace 0x7d1cfb8b "user"]
user=> (union #{1 2} #{2 3})  ;; won't work, because `union` has not been :refer'ed in the `user` namespace
CompilerException java.lang.RuntimeException: Unable to resolve symbol: union in this context, compiling:(NO_SOURCE_PATH:9:1)
user=> (cset/intersection #{1 2} #{2 3}) ;; won't work, because the `cset` alias has not been defined in the current namespace.
CompilerException java.lang.RuntimeException: No such namespace: cset, compiling:(NO_SOURCE_PATH:10:1)
user=>

TIP: You can find what aliases are defined in a given namespace by calling ns-aliases.

myapp.foo.bar=> (ns-aliases 'myapp.foo.bar)
{cset #object[clojure.lang.Namespace 0x4b2a01d4 "clojure.set"]}
  • In what namespace the Vars that you define (using for example (def …​) or (defn …​)) will exist.

For example, if the current namespace is myapp.foo.bar and you define a Var named my-favorite-number, you will be able to reference that Var as myapp.foo.bar/my-favorite-number from other namespaces:

$ clj
Clojure 1.9.0
user=> (ns myapp.foo.bar) ;; creating and switching to the `myapp.foo.bar` namespace - NOTE `ns` will be explained later in this guide
nil
myapp.foo.bar=> (def my-favorite-number 42) ;; defining a Var named `my-favorite-number`
#'myapp.foo.bar/my-favorite-number
myapp.foo.bar=> my-favorite-number
42
myapp.foo.bar=> (ns myapp.baz) ;; creating and switching to another namespace `myapp.baz`
nil
myapp.baz=> myapp.foo.bar/my-favorite-number ;; refering to `my-favorite-number`
42
myapp.baz=> (require '[myapp.foo.bar :as foobar]) ;; we can also use an alias to make it shorter
nil
myapp.baz=> foobar/my-favorite-number
42

You can find what the current namespace is by evaluating *ns*:

$ clj
Clojure 1.9.0
user=> *ns*
#object[clojure.lang.Namespace 0x7d1cfb8b "user"]

As you can see, by default, when you start a REPL with clj, the current namespace is user.

Creating a namespace with ns

You can create and switch to a new namespace by evaluating (ns MY-NAMESPACE-NAME):

$ clj
Clojure 1.9.0
user=> (ns myapp.foo-bar)
nil
myapp.foo-bar=> *ns*
#object[clojure.lang.Namespace 0xacdb094 "myapp.foo-bar"]
myapp.foo-bar=> (def x 42)
#'myapp.foo-bar/x

Note: when you switch to a new namespace, the names and aliases that were defined in the previous namespaces are no longer available:

$ clj
Clojure 1.9.0
user=> (ns myapp.ns1)
nil
myapp.ns1=> (def x 42)
#'myapp.ns1/x
myapp.ns1=> x
42
myapp.ns1=> (require '[clojure.string :as str])
nil
myapp.ns1=> (str/upper-case "hello")
"HELLO"
myapp.ns1=> (ns myapp.ns2)
nil
myapp.ns2=> x ;; won't work, because x has not been defined in namespace `myapp.ns2`
CompilerException java.lang.RuntimeException: Unable to resolve symbol: x in this context, compiling:(NO_SOURCE_PATH:0:0)
myapp.ns2=> (str/upper-case "hello") ;; won't work, because alias `str` has not been defined in namespace `myapp.ns2`
CompilerException java.lang.RuntimeException: No such namespace: str, compiling:(NO_SOURCE_PATH:9:1)

Switching to an existing namespace with in-ns

You can switch to an existing namespace by evaluating (in-ns 'MY-NAMESPACE-NAME). Here’s an example REPL session that creates a namespace myapp.some-ns, defines a Var named x in it, moves back to the user namespace, then moves again to myapp.some-ns:

$ clj
Clojure 1.9.0
user=> (ns myapp.some-ns) ;;;; creating the namespace `myapp.some-ns`
nil
myapp.some-ns=> *ns* ;; where are we?
#object[clojure.lang.Namespace 0xacdb094 "myapp.some-ns"]
myapp.some-ns=> (def x 42) ;; defining `x`
#'myapp.some-ns/x
myapp.some-ns=> (in-ns 'user) ;;;; switching back to `user`
#object[clojure.lang.Namespace 0x4b45dcb8 "user"]
user=> *ns* ;; where are we?
#object[clojure.lang.Namespace 0x4b45dcb8 "user"]
user=> (in-ns 'myapp.some-ns) ;;;; ...switching back again to `myapp.some-ns`
#object[clojure.lang.Namespace 0xacdb094 "myapp.some-ns"]
myapp.some-ns=> *ns* ;; where are we?
#object[clojure.lang.Namespace 0xacdb094 "myapp.some-ns"]
myapp.some-ns=> x ;; `x` is still here!
42

What happens if you in-ns to a namespace that has never been created? You will see strange things happening. For instance, you will not be able to define a function using defn:

$ clj
Clojure 1.9.0
user=> (in-ns 'myapp.never-created)
#object[clojure.lang.Namespace 0x22356acd "myapp.never-created"]
myapp.never-created=> (defn say-hello [x] (println "Hello, " x "!"))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: defn in this context, compiling:(NO_SOURCE_PATH:2:1)

Explanation: in this situation, in-ns creates the new namespace and switches to it like ns does, but it does a little less work than ns, because it does not automatically make available all the names defined in clojure.core, such as defn. You can fix that by evaluating (clojure.core/refer-clojure):

myapp.never-created=> (clojure.core/refer-clojure)
nil
myapp.never-created=> (defn say-hello [x] (println "Hello, " x "!"))
#'myapp.never-created/say-hello
myapp.never-created=> (say-hello "Jane")
Hello,  Jane !
nil

If you only use in-ns to switch to namespaces that have already been created, you won’t have to deal with these subtleties.

Working with libs

Most of the namespaces you will navigate at the REPL will already exist in source files or dependencies of your project, i.e in libs of your project.

There is an important usage precaution for switching to namespaces defined in libs:

If a namespace is defined in a lib of your project, always make sure you have loaded the lib in the REPL before switching to it.

How to make sure a lib is loaded

To make sure that a lib with namespace mylib.ns1 has been loaded in the REPL, you can do any one of the following:

  1. require it directly: (require '[mylib.ns1])

  2. load a namespace which itself requires mylib.ns1 (directly or indirectly).

  3. evaluate manually all the code in the source file mylib.ns1

Example: a project for greeting people

For example, assume a Clojure project with the following structure and content:

.
└── src
    └── myproject
        ├── person_names.clj
        └── welcome.clj
;; -----------------------------------------------
;; src/myproject/welcome.clj
(ns myproject.welcome
  (:require [myproject.person-names :as pnames])) ;; NOTE: `myproject.welcome` requires `myproject.person-names`

(defn greet
  [first-name last-name]
  (str "Hello, " (pnames/familiar-name first-name last-name)))


;; -----------------------------------------------
;; src/myproject/person_names.clj
(ns myproject.person-names
  (:require [clojure.string :as str]))

(def nicknames
  {"Robert"     "Bob"
   "Abigail"    "Abbie"
   "William"    "Bill"
   "Jacqueline" "Jackie"})

(defn familiar-name
  "What to call someone you may be familiar with."
  [first-name last-name]
  (let [fname (str/capitalize first-name)
        lname (str/capitalize last-name)]
    (or
      (get nicknames fname)
      (str fname " " lname))))

Here are 3 ways to make sure myproject.person-names is loaded:

$ clj ## APPROACH 1: requiring myproject.person-names directly
Clojure 1.9.0
user=> (require '[myproject.person-names])
nil
user=> myproject.person-names/nicknames ;; checking that the myproject.person-names was loaded.
{"Robert" "Bob", "Abigail" "Abbie", "William" "Bill", "Jacqueline" "Jackie"}
$ clj ## APPROACH 2: requiring myproject.welcome, which itself requires myproject.person-names
Clojure 1.9.0
user=> (require '[myproject.welcome])
nil
user=> myproject.person-names/nicknames ;; checking that the myproject.person-names was loaded.
{"Robert" "Bob", "Abigail" "Abbie", "William" "Bill", "Jacqueline" "Jackie"}
$ clj ## APPROACH 3: manually copying the code of myproject.person-names in the REPL.
Clojure 1.9.0
(ns myproject.person-names
  (:require [clojure.string :as str]))

(def nicknames
  {"Robert"     "Bob"
   "Abigail"    "Abbie"
   "William"    "Bill"
   "Jacqueline" "Jackie"})

(defn familiar-name
  "What to call someone you may be familiar with."
  [first-name last-name]
  (let [fname (str/capitalize first-name)
        lname (str/capitalize last-name)]
    (or
      (get nicknames fname)
      (str fname " " lname))))
nil
myproject.person-names=> myproject.person-names=> #'myproject.person-names/nicknames
myproject.person-names=> myproject.person-names=> #'myproject.person-names/familiar-name
myproject.person-names=> myproject.person-names/nicknames ;; checking that the myproject.person-names was loaded.
{"Robert" "Bob", "Abigail" "Abbie", "William" "Bill", "Jacqueline" "Jackie"}

TIP: you can see (among other things) what libs get loaded by using the :verbose tag in require:

$ clj
Clojure 1.9.0
user=> (require '[myproject.welcome] :verbose)
(clojure.core/load "/myproject/welcome")
(clojure.core/in-ns 'clojure.core.specs.alpha)
(clojure.core/alias 's 'clojure.spec.alpha)
(clojure.core/load "/myproject/person_names")
(clojure.core/in-ns 'myproject.person-names)
(clojure.core/alias 'str 'clojure.string)
(clojure.core/in-ns 'myproject.welcome)
(clojure.core/alias 'pnames 'myproject.person-names)
nil

How things can go wrong

Continuing with the above example project, here is a REPL session showing how things can go wrong if you switch to a lib namespace without loading it first:

$ clj
Clojure 1.9.0
user=> (ns myproject.person-names)
nil
myproject.person-names=> nicknames ;; #'nicknames won't be defined, because the lib has not been loaded.
CompilerException java.lang.RuntimeException: Unable to resolve symbol: nicknames in this context, compiling:(NO_SOURCE_PATH:0:0)
myproject.person-names=> (require '[myproject.person-names]) ;; won't fix the situation, because the namespaces has already been created
nil
myproject.person-names=> nicknames
CompilerException java.lang.RuntimeException: Unable to resolve symbol: nicknames in this context, compiling:(NO_SOURCE_PATH:0:0)

Enhancing your REPL workflow

At this point, you know enough to understand how the REPL works; we’ll now focus on giving you a more streamlined development experience with the REPL. There is a variety of things you may want to improve:

Switching between my editor and the REPL is tedious.

Most Clojure programmers don’t use the terminal-based REPL for everyday development: instead, they use a REPL integration in their editor, which enables them to write expressions directly in their editor buffer and have them evaluated in the REPL with one hotkey. See the Editor integrations section below for more details.

I want to do small experiments in Clojure, but it’s painful to write code in the default CLI tool.

As mentioned above, one solution could be to use an Editor integration; Note that some editors such as Nightcode are designed specifically to provide a 'batteries-included' experience for Clojure.

However, if setting up an editor is too heavy for your taste, there also exist more ergonomic terminal REPL clients:

I need to debug a program I’m running from the REPL.

The REPL can definitely help you do that: see the Debugging Tools and Techniques section below.

I want to use a REPL for ClojureScript.

When I make changes to my code, it’s often difficult to reflect that change in my running program: I have to do a lot of manual work in the REPL to make it happen..

I would like to save my REPL sessions in a 'notebook' format.

Gorilla REPL was made for this very purpose.

I want to use the REPL to connect to a live production system.

Editor integrations

All major Clojure editors support a way of evaluating code in the REPL without leaving the current code buffer, which reduces the amount of context switching a programmer has to do. Here’s what it looks like (the editor used in this example is Cursive):

Editor REPL integration

TIP: You can wrap some expressions in a (comment …​) block so that they don’t get evaluated by accident when the file is loaded:

;; you would NOT want this function to get called by accident.
(defn transfer-money!
  [from-accnt to-accnt amount]
  ...)

(comment
  (transfer-money! "accnt243251" "accnt324222" 12000)
  )

What to expect from an in-editor REPL integration?

Here are some common editor commands provided by REPL integrations. All major Clojure editors support a majority of them:

  • Send form before caret to REPL: evaluate the expression before the cursor in the REPL, in the namespace of the current file. Useful for experimenting in the context of the current namespace.

  • Send top-level form to REPL: evaluate the biggest expression in which the cursor is currently contained -typically a (defn …​) or (def …​) expression-in the namespace of the current file. Useful for defining or re-defining Vars in a namespace.

  • Load the current file in the REPL. Useful to avoid loading libs manually.

  • Switch the REPL’s namespace to current file: useful to avoid typing (in-ns '…​).

  • Show evaluation inline: displays the evaluation of the current expression next to it.

  • Replace expression with its evaluation: replaces the current expression in the editor with its evaluation (as printed by the REPL).

Debugging tools and techniques

While traditional debuggers can be used with Clojure, the REPL itself is a powerful debugging environment, because it lets you inspect and alter the flow of a running program. In this section, we’ll study some tools and techniques to leverage the REPL for debugging.

Printing in-flight values with prn

(prn …​) expressions can be added in strategic places in your code to print intermediary values:

(defn average
  "A buggy function computing the average of numbers"
  [numbers]
  (prn numbers) ;; HERE
  (/
    (+ numbers)
    (count numbers)))
#'user/average
user=> (average [12 14])
[12 14] ## HERE
ClassCastException Cannot cast clojure.lang.PersistentVector to java.lang.Number  java.lang.Class.cast (Class.java:3258)

TIP: you can combine prn with the (doto …​) macro, i.e (doto MY-EXPR prn), to make adding prn calls less invasive:

(defn average
  "A buggy function computing the average of numbers"
  [numbers]
  (/
    (+ (doto numbers prn)) ;; HERE
    (count numbers)))
Going further: spy macros

Some Clojure libraries provide 'enhanced' versions of prn that are more informative, by also printing information about the wrapped expression. For example:

  • the tools.logging logging library provides a spy macro to log an expression’s code along with its value

  • the spyscope lets you to insert these printing calls with very lightweight syntax.

Going further: tracing libraries

Tracing libraries such as tools.trace and Sayid can help you instrument larger portions of your code, for example by automatically printing all the function calls in a given namespace, or all intermediary values in a given expression.

Intercepting and saving values on-the-fly

Sometimes you want to do more with intermediary values than just print: you want to save them to conduct further experiments on them at the REPL. This can be done by inserting a (def …​) call inside the expression where the value appears:

(defn average
  [numbers]
  (let [sum (apply + numbers)
        n (count numbers)]
    (def n n) ;; HERE: saving the value of `n` in a Var.
    (/ sum n)))
user=> (average [1 2 3])
2
user=> n

This 'inline-def' technique is described in more depth in this blog post by Michiel Borkent.

Writing REPL-friendly programs

While interactive development at the REPL gives a lot of power to programmers, it also adds new challenges: programs must be designed so that they lend themselves well to REPL interaction, which is a new constraint to be vigilant of when writing code.[2]

Covering this topic extensively would take us too far for the scope of this guide, so we will merely provide some tips and resources to guide your own research and problem solving.


1. Note that what we call a Clojure lib is not necessarily a library: it can also be a source code file in your current project.
2. A similar phenomenon happens with the well-known technique of automated testing: while testing can bring a lot of value to programmers, it requires extra care to write code that is 'testable'. Just like tests, the REPL should not be an afterthought when writing Clojure code.

Original author: Valentin Waeselynck