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])
This expression makes all the names defined in the clojure.repl namespace available in the REPL. doc
You can print the API documentation of a given Var by evaluating (doc MY-VAR-NAME):
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
source
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
dir
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. apropos
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:
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
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.10.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=>
for a result which is a sequence of maps (like the above), 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
When a structure is too deeply nested, you can truncate the output by setting the print-level Var:
user=> (set! *print-level* 3)
3
user=> {:a {:b [{:c {:d {:e 42}}}]}} ;; a deeply nested data structure
{:a {:b [#]}}
You can undo this setting by evaluating (set! print-level nil).
Likewise, when a data structure contains long collections, you can limit the number of displayed item by setting the print-length Var:
user=> (set! print-length 3) 3 user=> (repeat 100 (vec (range 100))) ;; a data structure containing looooong collections. ([0 1 2 ...] [0 1 2 ...] [0 1 2 ...] ...)
Like the above, evaluate (set! print-length nil) to undo this setting.
print-level and print-length affect both ordinary REPL printing and pretty-pretting.
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 *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=>
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 it, so I gave up."
For instance, an Exception will be thrown if you divide a number by zero:
user=> (/ 1 0) Execution error (ArithmeticException) at user/eval163 (REPL:1). Divide by zero
By default, the REPL prints a two-line summary of the Exception. The first line reports the error phase (execution, compilation, macroexpansion, etc) and its location. The second line reports the cause.
This can be enough in many cases, but there is more information available.
First, you can visualize 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
xand
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. In the below REPL session, we can see that we calling our function with an empty vector of numbers led to dividing zero by zero:
user=> (average []) Execution error (ArithmeticException) at user/divide-verbose (REPL:6). Divide by zero user=> *e ;; notice the
:datakey 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 [user$average invokeStatic "NO_SOURCE_FILE" 10]} {:type clojure.lang.ExceptionInfo :message "Failed to divide 0 by 0" :data {:numerator 0, :denominator 0} :at [user$divide_verbose invokeStatic "NO_SOURCE_FILE" 9]} {:type java.lang.ArithmeticException :message "Divide by zero" :at [clojure.lang.Numbers divide "Numbers.java" 188]}] :trace [[clojure.lang.Numbers divide "Numbers.java" 188] [user$divide_verbose invokeStatic "NO_SOURCE_FILE" 6] [user$divide_verbose invoke "NO_SOURCE_FILE" 1] [user$average invokeStatic "NO_SOURCE_FILE" 7] [user$average invoke "NO_SOURCE_FILE" 1] [user$eval173 invokeStatic "NO_SOURCE_FILE" 1] [user$eval173 invoke "NO_SOURCE_FILE" 1] [clojure.lang.Compiler eval "Compiler.java" 7176] [clojure.lang.Compiler eval "Compiler.java" 7131] [clojure.core$eval invokeStatic "core.clj" 3214] [clojure.core$eval invoke "core.clj" 3210] [clojure.main$repl$read_eval_print__9068$fn__9071 invoke "main.clj" 414] [clojure.main$repl$read_eval_print__9068 invoke "main.clj" 414] [clojure.main$repl$fn__9077 invoke "main.clj" 435] [clojure.main$repl invokeStatic "main.clj" 435] [clojure.main$repl_opt invokeStatic "main.clj" 499] [clojure.main$main invokeStatic "main.clj" 598] [clojure.main$main doInvoke "main.clj" 561] [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" 705] [clojure.main main "main.java" 37]]}
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+") ;; opens the Javadoc page for java.util.Pattern in a Web browser
true
user=> (jdoc/javadoc java.util.regex.Pattern) ;; equivalent to the above
true
clojure.inspector lets you open GUI-based visualizations of data
Sometimes, the printed representation of a value in the REPL is not very informative; sometimes, it can even be misleading as to the nature of that value.[1] This often happens with values which are obtained via Java interop.
As an example, we’ll create an InputStream object using the clojure.java.io lib. If you don’t know what an InputStream is, all the better - the point of this section is to teach you how to find your footing in uncharted territory:
user=> (require '[clojure.java.io :as io])
nil
user=> (def v (io/input-stream "https://www.clojure.org"))
;; NOTE won't work if you're not connected to the Internet
#'user/v
user=> v
#object[java.io.BufferedInputStream 0x4ee37ca3 "java.io.BufferedInputStream@4ee37ca3"]
The above code sample defined an InputStream named v.
Now imagine you don’t know where v comes from, and let’s try to interact with it at the REPL so as to gain more understanding of it. Viewing the type hierarchy using type and ancestors
The printed representation of v tells us one thing about it: its runtime type, in this case java.io.BufferedInputStream. The type of a value can help us know what operations we may call on it. We can evaluate (type v) to obtain the concrete type of v, and (ancestors (type v)) to obtain its entire type hierarchy:
user=> (type v)
;; what is the type of our obscure value?
java.io.BufferedInputStream
user=> (ancestors (type v))
#{java.io.InputStream java.lang.AutoCloseable java.io.Closeable java.lang.Object java.io.FilterInputStream}
As we saw in the previous section, we can use the clojure.java.javadoc lib to view online documentation about a Java type:
user=> (require '[clojure.java.javadoc :as jdoc])
nil
user=> (jdoc/javadoc java.io.InputStream)
;; should open a web page about java.io.InputStream
true
Javadoc is helpful, but sometimes Javadoc won’t even be available. In such cases, we can use the REPL itself to inspect types, via Java reflection.
We can use the clojure.reflect/reflect function to obtain information about a Java type as a plain Clojure data structure:
user=> (require '[clojure.reflect :as reflect])
nil
user=> (reflect/reflect java.io.InputStream)
{:bases #{java.lang.Object java.io.Closeable}, :flags #{:public :abstract}, :members #{#clojure.reflect.Method{:name close, :return-type void, :declaring-class java.io.InputStream, :parameter-types [], :exception-types [java.io.IOException], :flags #{:public}} #clojure.reflect.Method{:name mark, :return-type void, :declaring-class java.io.InputStream, :parameter-types [int], :exception-types [], :flags #{:public :synchronized}} #clojure.reflect.Method{:name available, :return-type int, :declaring-class java.io.InputStream, :parameter-types [], :exception-types [java.io.IOException], :flags #{:public}} #clojure.reflect.Method{:name read, :return-type int, :declaring-class java.io.InputStream, :parameter-types [], :exception-types [java.io.IOException], :flags #{:public :abstract}} #clojure.reflect.Method{:name markSupported, :return-type boolean, :declaring-class java.io.InputStream, :parameter-types [], :exception-types [], :flags #{:public}} #clojure.reflect.Field{:name MAX_SKIP_BUFFER_SIZE, :type int, :declaring-class java.io.InputStream, :flags #{:private :static :final}} #clojure.reflect.Constructor{:name java.io.InputStream, :declaring-class java.io.InputStream, :parameter-types [], :exception-types [], :flags #{:public}} #clojure.reflect.Method{:name read, :return-type int, :declaring-class java.io.InputStream, :parameter-types [byte<>], :exception-types [java.io.IOException], :flags #{:public}} #clojure.reflect.Method{:name skip, :return-type long, :declaring-class java.io.InputStream, :parameter-types [long], :exception-types [java.io.IOException], :flags #{:public}} #clojure.reflect.Method{:name reset, :return-type void, :declaring-class java.io.InputStream, :parameter-types [], :exception-types [java.io.IOException], :flags #{:public :synchronized}} #clojure.reflect.Method{:name read, :return-type int, :declaring-class java.io.InputStream, :parameter-types [byte<> int int], :exception-types [java.io.IOException], :flags #{:public}}}}
Now, that is a very hairy data structure. Fortunately, we have learned how to deal with hairy data structures in the first section of this chapter: pretty-printing to the rescue! Let’s use pretty-printing to display the methods exposed by java.io.InputStream in a table:
user=> (->> (reflect/reflect java.io.InputStream) :members (sort-by :name) (pp/print-table [:name :flags :parameter-types :return-type]) )
| :name | :flags | :parameter-types | :return-type | |----------------------+----------------------------+------------------+--------------| | MAX_SKIP_BUFFER_SIZE | #{:private :static :final} | | | | available | #{:public} | [] | int | | close | #{:public} | [] | void | | java.io.InputStream | #{:public} | [] | | | mark | #{:public :synchronized} | [int] | void | | markSupported | #{:public} | [] | boolean | | read | #{:public :abstract} | [] | int | | read | #{:public} | [byte<>] | int | | read | #{:public} | [byte<> int int] | int | | reset | #{:public :synchronized} | [] | void | | skip | #{:public} | [long] | long | nil
For example, this tells us that we can call a .read method on v with no arguments, which will return an int:
user=> (.read v)
60
user=> (.read v)
33
user=> (.read v)
68
Without any prior knowledge, we have managed to learn that v is an InputStream, and read bytes from it.