# HG changeset patch # User Robert McIntyre # Date 1318775541 25200 # Node ID 1c7ace5054ac5254a16099f34beee8b0d75f5fd7 initial commit diff -r 000000000000 -r 1c7ace5054ac .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Sun Oct 16 07:32:21 2011 -0700 @@ -0,0 +1,3 @@ +syntax: glob +src* +html* \ No newline at end of file diff -r 000000000000 -r 1c7ace5054ac org/no_parens.org --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/org/no_parens.org Sun Oct 16 07:32:21 2011 -0700 @@ -0,0 +1,102 @@ +#+title: Calling it quits without parentheses +#+author: Robert McIntyre & Dylan Holmes +#+EMAIL: rlm@mit.edu +#+MATHJAX: align:"left" mathml:t path:"../MathJax/MathJax.js" +#+STYLE: +#+OPTIONS: H:3 num:t toc:t \n:nil @:t ::t |:t ^:t -:t f:t *:t <:t +#+SETUPFILE: ../templates/level-0.org +#+INCLUDE: ../templates/level-0.org + +[TABLE-OF-CONTENTS] + +# * Calling it quits without parentheses +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. + +#+srcname: header +#+begin_src clojure :results silent +(ns abomination.no-parens + (:use clojure.contrib.def)) +#+end_src + +* By modifying =toString= +#+srcname: toString +#+begin_src clojure +(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") +#+end_src + +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. + +#+begin_src clojure :exports both +(binding [*compile-path* "/home/r/aurellem/classes"] + (compile 'abomination.no-parens)) +#+end_src + +#+results: +: abomination.no-parens + +* By wrapping the command in a lazy sequence +#+srcname: lazy-seq +#+begin_src clojure :results silent +(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") +#+end_src + +* By =delay=-ing the command +#+srcname: delay +#+begin_src clojure :results silent +(in-ns 'abomination.no-parens) +(defvar quit** (delay (System/exit 0)) + "when this is evaulated at the REPL, it will exit the JVM.") +#+end_src + +The same thing, accomplished in a much more elegant and clojureish +way. + +#+begin_src clojure :tangle no_parens.clj :results silent :exports none :noweb yes +<
> +<> +<> +<> +#+end_src + +# STUD CRUFT PIZZA + +#+begin_quote +And death i think is no parenthesis +\mdash{}E. E. Cummings +#+end_quote diff -r 000000000000 -r 1c7ace5054ac readme.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/readme.txt Sun Oct 16 07:32:21 2011 -0700 @@ -0,0 +1,2 @@ +Here, Dylan and I use some neat tricks to give a "quit" command to +clojure which can be called with no parens.