Mercurial > abomination
view org/no_parens.org @ 4:be0be0a90ba4 tip
s.
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Mon, 02 Mar 2015 12:35:43 -0800 |
parents | 06131b93e54f |
children |
line wrap: on
line source
1 #+title: Calling it quits without parentheses2 #+author: Robert McIntyre & Dylan Holmes3 #+EMAIL: rlm@mit.edu4 #+SETUPFILE: ../../aurellem/org/setup.org5 #+INCLUDE: ../../aurellem/org/level-0.org8 # * Calling it quits without parentheses9 Is it possible to make a =quit= command for Clojure such that simply10 typing the word =quit= at an REPL exits the REPL? An intuitive =quit=11 command would be especially useful for people new to Lisp syntax or12 the REPL; the challenge is to make a genuine Clojure command that13 executes without being called with parentheses. We found three14 solutions.16 #+srcname: header17 #+begin_src clojure :results silent18 (ns abomination.no-parens19 (:use clojure.contrib.def))20 #+end_src22 * By modifying =toString=23 #+srcname: toString24 #+begin_src clojure25 (in-ns 'abomination.no-parens)26 (gen-class :name abomination.no-parens.Quit27 :prefix quit-)29 (defn quit-toString30 [this]31 (System/exit 0))34 (defvar quit (abomination.no-parens.Quit.)35 "a sneaky way to support a `quit` command")36 #+end_src38 When you type any variable at the REPL, the REPL attempts to print it39 as a nicely-formatted string by calling its =toString= method. Our40 trick is to define a class with a =toString= method that exits the41 REPL; this trick ensures that any variable of that class will close42 the REPL when the REPL attempts to print it.44 First, we use =gen-class= to make a new class named Quit; in that same45 line, we use =:prefix= to establish the convention that any function46 named =quit-[something]= will be adopted as the =[something]= method47 for the newly-defined Quit class. We use this convention to write our48 own =toString= method for Quit.50 Next, we define a suitable =toString= method for the Quit class so51 that attempting to print an instance of the Quit class has the effect52 of closing the REPL. We do this by defining a function =quit-toString=53 which closes the REPL; by the convention established above, the Quit54 class automatically adopts =quit-toString= as its =toString= method.56 Finally, we use =defvar= to create an instance of the Quit class; we57 name this instance =quit=. Now when you type =quit= into the REPL, the58 REPL executes the =toString= method of the Quit class, exiting the59 REPL instead of returning a string.61 #+begin_src clojure :exports both62 (binding [*compile-path* "/home/r/proj/abomination/classes"]63 (compile 'abomination.no-parens))65 #+end_src67 #+results:68 : abomination.no-parens70 * By wrapping the command in a lazy sequence71 #+srcname: lazy-seq72 #+begin_src clojure :results silent73 (in-ns 'abomination.no-parens)74 (defvar quit* (lazy-seq :the-great-bringer-of-death! (System/exit 0))75 "the first time it's evaulated it will kill the JVM")76 #+end_src78 * By =delay=-ing the command79 #+srcname: delay80 #+begin_src clojure :results silent81 (in-ns 'abomination.no-parens)82 (defvar quit** (delay (System/exit 0))83 "when this is evaulated at the REPL, it will exit the JVM.")84 #+end_src86 The same thing, accomplished in a much more elegant and clojureish87 way.89 # STUD CRUFT PIZZA91 #+begin_quote92 And death i think is no parenthesis93 \mdash{}E. E. Cummings94 #+end_quote97 * COMMENT code generation98 #+begin_src clojure :tangle ../src/abomination/no_parens.clj :results silent :exports none :noweb yes99 <<header>>100 <<toString>>101 <<lazy-seq>>102 <<delay>>103 #+end_src