I think you might be missing the main "aha!" of clojure REPLs vs REPLs in non-homoiconic languages: you can very easily execute small parts of the program you're editing without re-typing the code.
In emacs, for instance, you often use `eval-last-sexp`, by default bound to C-x C-e. This lets you move your cursor to a particular point in the file, often deep in a function, and get the results of just the form(s) you're pointing at.
This is a superpower! It lets you test small pieces of your code without writing any test harnesses or scaffolding. Try it with an editor that embeds the repl and has these commands, and you'll never want to develop any other way.
It does cause you to want to structure your code in 'repl-friendly' ways, so that you can, say, restart your main server or reset your state without restarting the whole process.
When you evaluate a form deep in a function, how do you handle variables that are defined "outside"? How can you evaluate such expressions?
Cider (the clojure plugin for emacs) has a variant that prompts you for the the values for those variables.
Oh nice. That's one place where Clojure beats Common Lisp then..
Does it? Asking for a value when encountering an unbound variable is a default restart
$ sbcl
This is SBCL 2.1.1.52.HEAD.321-f8a57bcca, an
implementation of ANSI Common Lisp.
More information about SBCL is available at
.
SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
\* (\* x x)
debugger invoked on a UNBOUND-VARIABLE in thread
#:
The variable X is unbound.
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [CONTINUE ] Retry using X.
1: [USE-VALUE ] Use specified value.
2: [STORE-VALUE] Set specified value and use it.
3: [ABORT ] Exit debugger, returning to top level.
(SB-INT:SIMPLE-EVAL-IN-LEXENV X #)
0] 2 Enter a form to be evaluated: 3
9
\*Yeah, in fact, Clojure needs special tooling for this, while it’s built into CL’s execution model.