A normal Clojure REPL (or prompt) in a terminal window is by default a bit touchy about infinite seqs, deeply nested structures, and long-running operations. Any of these can cause your REPL to wander off into the weeds, busy spinning, perhaps printing pages of useless data, with the only apparent remedy being to press CTRL-C, which generally kills the entire JVM, Clojure and all, and dumps you back at your operating system prompt.
It's unfortunate that this is the default, but Clojure's youth shows particularly when it come to tools and settings like this. Happily it's sufficiently mature to provide several solutions that are not difficult to apply.
Run-away trains
The most common of the problems listed above is the infinite seq. Such a seq is easy to create, easy to print, and can result in an run-away REPL. The solution: setting your *print-length* to something short of infinity. I recommend 103:
(set! *print-length* 103)
Now it's safe to print infinite sequences:
(iterate inc 0)
;=> (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 ...)
Note the ... at the end of the list which indicates there was more to print, but Clojure is respecting our requested limit and giving up after 103 items. I've been mocked upon occasion for choosing 103, as if 102 is insufficient and 104 dangerous. Of course it's not so important exactly what you pick, so I'm happy to keep my rationale to myself.
Run-away onions
But *print-length* won't help you in the case of infinitely recursive structures, data nested inside data like layers of an onion. While less common, such nesting can be deep enough that it can still be a problem. To limit printing of recursive structures, use *print-level*. Usually 15 is about right for me:
(set! *print-level* 15)
Now it's safe to print infinitely recursive structures:
(let [x (atom 0)] (reset! x {:deeper x}))
;=> {:deeper #<Atom@4cb533b8: {:deeper #<Atom@4cb533b8:
{:deeper #<Atom@4cb533b8: {:deeper #<Atom@4cb533b8:
{:deeper #<Atom@4cb533b8: {:deeper #<Atom@4cb533b8:
{:deeper #<Atom@4cb533b8: {:deeper #}>}>}>}>}>}>}>}
Again you get a little textual indicator that print is giving up, in this case it's just the # at the deepest level.
Run-away exercise bikes
But these settings only help take control of run-away printing. Sometimes the REPL gets hung up doing something other than printing, sitting there spinning away like a stationary bike, and neither of these settings will help you. My final advice is to use repl-utils to register your REPL thread as killable by CTRL-C:
(require 'clojure.contrib.repl-utils) (clojure.contrib.repl-utils/add-break-thread!)
Now when you press CTRL-C, instead of shutting down the whole JVM, an exception will be thrown within the REPL thread, which is usually exactly what you need to halt run-away computation. Note that repl-utils does this using a deprecated Java API that is described as unsafe. And yet it remains useful for just such circumstances. For example:
(deref (promise))
Look at that -- instant deadlock! Now press CTRL-C, and you get:
java.lang.Exception: SIGINT (NO_SOURCE_FILE:0)
...and you're back to REPL prompt. But now you've violated Java, so I'd recommend saving what you need to save and then restart your JVM anyway. If you don't, weird things can happen. For example if you run the above deref-promise example again immediately, it may fail with a slightly different exception, even before you press CTRL-C. Similar strangeness can occur if you press CTRL-C at the REPL when no operation is running, though in that case it usually just kills your next expression, whatever it is.
Hopefully by setting your *print-length*, *print-level*, and break-thread, you can feel more comfortable at the REPL with less fear of getting stuck.
- The Joy of Clojure
- Thinking the Clojure Way
by Michael Fogus and Chris Houser
Well, now you’ve got me curious. What’s your personal reasoning for 103?
(set! *print-length* 103)
Thanks. This is really helpful. How many times have I killed my REPL due to infinite lists?
Heh. Well, something around 100 seems nice because that’s usually more than enough for me to see what’s going on, but not so much that it’s going to scroll too much off the top of my window. But exactly 100 is no good because then (range 100) looks rather like (iterate inc 0), even though it’s a very different thing. 103 is just enough more, and a strange enough number, that it’s likely I’ll notice the seq is being cut off by *print-length*, and not by whatever code is producing the seq.
Good tip! It would have spared me all of this: http://whollyweirdwyrd.blogspot.com/2010/01/recursive-walk-on-string.html
I wonder if it would be better to have these value set to some default values?
I second Nicolas — might be nice to have this set by default, though the CTRL-C trick would have to wait until add-break-thread is in core. Perhaps you could bring this up with Rich?