REPL stands for read-eval-print-loop, it is an interactive programming environment where a user may write a code directly into a terminal, the code is read, evaluated, the result is printed and the user can type a new code again. The environment has the fastest feedback to the user, because the result is printed immediately. This provides a good place where the user can start and play with the code and shape it. Let’s start with real examples.
We will use Leiningen (https://leiningen.org), but there are more ways to install REPL on you computer (see more https://clojure.org/guides/repl/launching_a_basic_repl).
When you have installed the REPL it can be started by typing
The output should be like the following:
nREPL server started on port 53767 on host 127.0.0.1 - nrepl://127.0.0.1:53767 REPL-y 0.4.3, nREPL 0.6.0 Clojure 1.10.0 Java HotSpot(TM) 64-Bit Server VM 10.0.1+10 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=>
In the output we can see a few things:
- The REPL is a program running as a server on port 53767
- nREPL version is 0.6.0
- We run Clojure 1.10.1
- We use JVM 10.0.1
- We can see a few hints on how to display documentation and etc.
- The REPL can be close by hitting Control+D or calling (exit) or (quit)
- Previous results of expressions are stored in *1, *2, *3 vars or an exception in *e
So let’s start with something really simple e.g.:
user=> (+ 1 1) 2 user=>
Number 2 is what we’ve expected. Let’s type something more interesting:
user=> (map inc (range 10)) (1 2 3 4 5 6 7 8 9 10) user=>
The map function generates a lazy sequence of incremented numbers from 1 to 10. The interesting thing is that we can see the result as a list instead of a lazy sequence. How is it possible? The REPL evaluated the lazy sequence for us and printed it. Let’s see:
user=> (type (map inc (range 10))) clojure.lang.LazySeq user=>
Be careful if you try to print out an infinite sequence or really huge data. Because the program behaves the same as we are used to in save-reload-try (when we call the program by hitting JVM from a terminal or URL) scenario.
Indeed, we can define a function and use it:
user=> (defn neg [x] (* -1 x)) #'user/neg user=> (map neg (range 10)) (0 -1 -2 -3 -4 -5 -6 -7 -8 -9) user=>
Or we can read from a file as we do in a general Clojure program:
user=> (slurp "/Users/lukas/file.txt") "Hallo\n" user=>
If we want to use other namespace we can simply require and use it:
user=> (require '[clojure.string :as string]) nil user=> (string/lower-case "QWERTY") "qwerty" user=>
Using REPL directly from your editor
Using the REPL from a terminal is handy, but it could become very cumbersome when the code becomes bigger and functions longer. Nothing is lost! As we saw before the REPL listens on some port (in output above 58656), so we can connect from an editor to that port and send a code from the editor to the REPL and display the output in the editor.
This is enough to know how to use it, let’s go to some examples. The examples will be shown in Spacemacs (https://www.spacemacs.org – a popular editor), but of course it’s possible to connect it from any editor with a plugin (if needed). Here you can see how to connect to the REPL from Cursive IDE https://cursive-ide.com/userguide/first-repl.html.
Open a new file in Spacemacs simply by calling it from the terminal
emacs user.clj &
This command opens Spacemacs (in background because of &) and creates a new file. Start the REPL by:
From Spacemacs you can connect to the started REPL by hitting:
SPC m s j c
Sometimes you can find M-x instead of SPC when reading the documentation for Emacs/Spacemacs. The reason is that M-x is a more general term. See our Spacemacs cheatsheet https://flexiana.com/2019/07/emacs-for-clojure-cheatsheet.
If Spacemacs is new for you SPC is Space key, m s and i are normal keys on your keyboard. You could be asked if you would like to start a REPL without a project, just answer yes (by hitting Y key). If everything went well the REPL should be started.
You can find more information on https://develop.spacemacs.org/layers/+lang/clojure/README.html#repl
Edit the file:
(ns user) (map inc (range 0 10))
And send the content to the REPL via calling SPC m s b. The output should be like this:
=> (1 2 3 4 5 6 7 8 9 10)
Let’s define a function and use it, so alter the file to:
(ns user) (defn neg [x] (* -1 x)) (map neg (range 0 10))
And send it (SPC m s b), the result should be:
=> (0 -1 -2 -3 -4 -5 -6 -7 -8 -9)
We showed how to run and execute a code in a REPL. Also we saw that it’s possible to send a code from an editor to the REPL and execute it. This option is very useful, because it provides a way to test and shape a program by playing with it and it’s a good practice as a complement to other methodologies like TDD (Test Driven Development).
The usage of the REPL just as a playground is not the only option we have. The REPL could be used for:
- Running tests
- Querying databases, HTTP calls, …
- Playing with 3rd party libraries (of course including Java libraries)
To find more documentation and examples see the official documentation https://clojure.org/guides/repl/introduction.