Calling it quits without parentheses
aurellem ☉
Is it possible to make a quit
command for Clojure such that simply
typing the word quit
at an REPL exits the REPL? An intuitive quit
command would be especially useful for people new to Lisp syntax or
the REPL; the challenge is to make a genuine Clojure command that
executes without being called with parentheses. We found three
solutions.
(ns abomination.no-parens (:use clojure.contrib.def))
1 By modifying toString
(in-ns 'abomination.no-parens) (gen-class :name abomination.no-parens.Quit :prefix quit-) (defn quit-toString [this] (System/exit 0)) (defvar quit (abomination.no-parens.Quit.) "a sneaky way to support a `quit` command")
When you type any variable at the REPL, the REPL attempts to print it
as a nicely-formatted string by calling its toString
method. Our
trick is to define a class with a toString
method that exits the
REPL; this trick ensures that any variable of that class will close
the REPL when the REPL attempts to print it.
First, we use gen-class
to make a new class named Quit; in that same
line, we use :prefix
to establish the convention that any function
named quit-[something]
will be adopted as the [something]
method
for the newly-defined Quit class. We use this convention to write our
own toString
method for Quit.
Next, we define a suitable toString
method for the Quit class so
that attempting to print an instance of the Quit class has the effect
of closing the REPL. We do this by defining a function quit-toString
which closes the REPL; by the convention established above, the Quit
class automatically adopts quit-toString
as its toString
method.
Finally, we use defvar
to create an instance of the Quit class; we
name this instance quit
. Now when you type quit
into the REPL, the
REPL executes the toString
method of the Quit class, exiting the
REPL instead of returning a string.
(binding [*compile-path* "/home/r/proj/abomination/classes"] (compile 'abomination.no-parens))
abomination.no-parens
2 By wrapping the command in a lazy sequence
(in-ns 'abomination.no-parens) (defvar quit* (lazy-seq :the-great-bringer-of-death! (System/exit 0)) "the first time it's evaulated it will kill the JVM")
3 By delay
-ing the command
(in-ns 'abomination.no-parens) (defvar quit** (delay (System/exit 0)) "when this is evaulated at the REPL, it will exit the JVM.")
The same thing, accomplished in a much more elegant and clojureish way.
And death i think is no parenthesis —E. E. Cummings