- Clojure for Java Developers
- Eduardo Díaz
- 903字
- 2021-07-16 09:49:47
Using a REPL
One of the main advantages of Clojure (and Lisp) is interactive development, the REPL is the base of what can be achieved with interactive programming, it allows you to connect to a running VM running Clojure and execute or modify code on the fly.
There is a story about how NASA was able to debug and correct a bug on a $100 million piece of hardware that was 100 million miles away (http://www.flownet.com/gat/jpl-lisp.html).
We have that same power with Clojure and Leiningen and invoking it is very simple, you just need a single command:
lein repl
This is what you'll get after running the preceding command:

Let's go into a bit more detail, as we can see we are running with the following programs:
- Java 8
- Clojure 1.6.0
We can also get some nice suggestions on how to see documentation, source
, Javadoc
, and previous errors.
The nREPL protocol
One particular thing that is important to note is the nREPL protocol; Someday it might grant us the power to go into a machine running 100 million miles away.
When you fire up your REPL, the first thing you see is:
nREPL server started on port 55995 on host 127.0.0.1 - nrepl://127.0.0.1:55995 REPL-y 0.3.5, nREPL 0.2.6
What it is saying is that there's a Clojure process running an nREPL server on port 55995
. We have connected to it using a very simple client that allows us to interact with the Clojure process.
The really interesting bit is that you can connect to a remote host just as easily; let's try attaching an REPL to the same process by simply typing the following command:
lein repl :connect localhost:55995
Most IDEs have a good integration with Clojure and most of them use this exact mechanism, as clients that work a little more intelligently.
Hello world
Now that we are inside the REPL, (any of the two) let's try writing our first expression, go on and type:
"Hello world"
You should get back a value from the REPL saying Hello world
, this is not really a program, and it is the Hello world
value printed back by the print phase of the REPL.
Let's now try to write our first Lisp form:
(println "Hello world")
This first expression looks different from what we are used to, it is called an S-expression and it is the standard Lisp way.
There are a couple of things to remember with S-expressions:
- They are lists (hence, the name, Lisp)
- The first element of the list is the action that we want to execute, the rest are the parameters of that action (one two three).
So we are asking for the string Hello world
to be printed, but if we look a bit closer at the output, as shown in the following screenshot, there is a nil
that we weren't expecting:

The reason for this is that the println
function returns the value nil
(Clojure's equivalent for null) after printing Hello world
.
Note
In Clojure, everything has a value and the REPL will always print it back for you.
REPL utilities and conventions
As we saw, the Leiningen nREPL client prints help text; but how does that work? Let's explore some of the other utilities that we have.
Try each of them to get a feeling of what it does with the help of the following table:

Let's check how these functions work:
user=> (javadoc java.util.List) ;; Should open the javadoc for java.util.List user=> (doc doc) ------------------------- clojure.repl/doc ([name]) Macro Prints documentation for a var or special form given its name nil user=> (source doc) (defmacro doc "Prints documentation for a var or special form given its name" {:added "1.0"} [name] (if-let [special-name ('{& fn catch try finally try} name)] (#'print-doc (#'special-doc special-name)) (cond (special-doc-map name) `(#'print-doc (#'special-doc '~name)) (find-ns name) `(#'print-doc (#'namespace-doc (find-ns '~name))) (resolve name) `(#'print-doc (meta (var ~name)))))) nil
Tip
Downloading the example code
You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
What you are seeing here is metadata pertaining to the doc
function; Clojure has the ability to store metadata about every function or var
you use. Most of the Clojure core functions include a doc string and the source of the function and this is something that will become very handy in your day to day work.
Besides these functions, we also get easy access to the latest three values and the latest exceptions that happened in the REPL, let's check this out:
user=> 2 2 user=> 3 3 user=> 4 4 user=> (* *1 *2 *3) ;; We are multiplying over here the last three values 24 ;;We get 24! user=> (/ 1 0) ;; Let's try dividing by zero ArithmeticException Divide by zero clojure.lang.Numbers.divide (Numbers.java:156) user=> *e #<ArithmeticException java.lang.ArithmeticException: Divide by zero> user=> (.getMessage *e) "Divide by zero"
Note
*e
gives you access to the actual plain old Java exception object, so you can analyze and introspect it at runtime.
You can imagine the possibilities of being able to execute and introspect code with this, but what about the tools that we are already used to? How can we use this with an IDE?
Let's check now how to create a new Clojure project, we'll use Leiningen from the command line to understand what is happening.
- 騰訊iOS測試實踐
- JavaScript 網頁編程從入門到精通 (清華社"視頻大講堂"大系·網絡開發視頻大講堂)
- C語言程序設計實訓教程
- 用Python實現深度學習框架
- Instant Ext.NET Application Development
- BeagleBone Black Cookbook
- Android Wear Projects
- 智能手機故障檢測與維修從入門到精通
- 官方 Scratch 3.0 編程趣味卡:讓孩子們愛上編程(全彩)
- ASP.NET開發寶典
- Visual C#(學習筆記)
- C語言從入門到精通(微視頻精編版)
- Unity與C++網絡游戲開發實戰:基于VR、AI與分布式架構
- 程序員的算法趣題2
- iOS程序員面試筆試真題與解析