diff --git a/Environment.hs b/Environment.hs
--- a/Environment.hs
+++ b/Environment.hs
@@ -18,23 +18,25 @@
 along with haskeem; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
-$Id: environment.hs,v 1.12 2009-08-06 05:05:15 uwe Exp $ -}
+$Id: environment.hs,v 1.14 2010-01-05 05:23:34 uwe Exp $ -}
 
 module Environment (isBound, getVar, setVar,
                     defineVar, bindVars, dumpEnv) where
 import Prelude
+import Data.Maybe
 import IO
 import Control.Monad.Error as CME
 import Data.IORef
 
 import LispData
 
+liftRead :: MonadIO m => IORef a -> m a
 liftRead = liftIO . readIORef
 
 isBound :: Env -> String -> IO Bool
 isBound envRef var =
   do env <- liftIO (readIORef envRef)
-     return (maybe False (const True) (lookup var env))
+     return (isJust (lookup var env))
 
 getVar :: Env -> String -> IOThrowsError LispVal
 getVar envRef var =
@@ -46,7 +48,7 @@
 setVar envRef var value =
   do env <- liftRead envRef
      maybe (throwError (UnboundVar "Setting an unbound variable" var))
-           (liftIO . (flip writeIORef value))
+           (liftIO . flip writeIORef value)
            (lookup var env)
      return value
 
@@ -64,10 +66,16 @@
         addBinding (var, value) = do ref <- newIORef value
                                      return (var, ref)
 
-dumpEnv :: Env -> Handle -> IOThrowsError LispVal
-dumpEnv envRef port = liftRead envRef >>= doDump
+-- The lastkey argument is for internal debugging: pass a non-empty string
+-- in, and the dump will stop before printing that symbol... useful for
+-- shortening the output. Not currently accessible at the scheme level.
+
+dumpEnv :: Env -> Handle -> String -> IOThrowsError LispVal
+dumpEnv envRef port lastkey = liftRead envRef >>= doDump
   where doDump [] = return lispTrue
         doDump ((key, vref):vars) =
-          do val <- liftRead vref
-             liftIO (hPutStrLn port (key ++ " -> " ++ (show val)))
-             doDump vars
+          if key == lastkey
+             then return lispTrue
+             else do val <- liftRead vref
+                     liftIO (hPutStrLn port (key ++ " -> " ++ show val))
+                     doDump vars
diff --git a/Evaluator.hs b/Evaluator.hs
--- a/Evaluator.hs
+++ b/Evaluator.hs
@@ -18,8 +18,10 @@
 along with haskeem; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
-$Id: evaluator.hs,v 1.40 2009-08-08 05:08:59 uwe Exp $ -}
+$Id: evaluator.hs,v 1.51 2010-01-18 00:08:49 uwe Exp $ -}
 
+{-# LANGUAGE FlexibleContexts #-}
+
 module Evaluator (evalLisp, evalPP) where
 import Prelude
 import IO
@@ -32,24 +34,30 @@
 import Environment
 import Library
 
-errNumArgs name want got = throwError (NumArgs name want got)
-errTypeMismatch name want got = throwError (TypeMismatch name want got)
-errBadForm name args =
-  throwError (BadSpecial ("bad " ++ name ++ " form") (List args))
+errNumArgs :: MonadError LispError m =>
+  String -> Integer -> [LispVal] -> m a
+errNumArgs name want = throwError . NumArgs name want
 
+errTypeMismatch :: MonadError LispError m =>
+  String -> String -> LispVal -> m a
+errTypeMismatch name want = throwError . TypeMismatch name want
+
+errBadForm :: MonadError LispError m => String -> [LispVal] -> m a
+errBadForm name =
+  throwError . BadSpecial ("bad " ++ name ++ " form") . List
+
 -- Debugging output: either inside haskeem while tracing something,
 -- or inside haskeem while debugging haskeem
 
-remark str = liftIO (hPutStrLn stderr str)
-
-progError = error "internal error!"
+remark :: MonadIO m => String -> m ()
+remark = liftIO . hPutStrLn stderr
 
-{-# INLINE mapML #-}
+mapML :: Monad m => (a -> m LispVal) -> [a] -> m LispVal
 mapML fn lst = mapMLA (List []) fn lst
   where mapMLA r _ [] = return r
-        mapMLA ro fn (x:xs) =
-           do rn <- fn x
-              mapMLA rn fn xs
+        mapMLA _ f (x:xs) =
+           do rn <- f x
+              mapMLA rn f xs
 
 isTrue :: LispVal -> Bool
 isTrue (Boolean False) = False
@@ -60,9 +68,9 @@
 
 uniqCheck :: String -> [LispVal] -> Bool
 uniqCheck _ [] = True
-uniqCheck name ((List ((Symbol var):_)):rest) =
+uniqCheck name ((List (Symbol var : _)) : rest) =
   if name == var then False else uniqCheck name rest
-uniqCheck _ _ = progError
+uniqCheck _ _ = progError "uniqCheck"
 
 -- Check the variable bindings in the various forms of "let".
 -- The "uniq" boolean argument specifies whether or not multiple
@@ -70,8 +78,8 @@
 
 letCheck :: Bool -> [LispVal] -> Bool
 letCheck _ [] = True
-letCheck uniq ((List [Symbol var, _]):rest) =
-  letCheck uniq rest && ((not uniq) || (uniq && uniqCheck var rest))
+letCheck uniq ((List [Symbol var, _]) : rest) =
+  letCheck uniq rest && (not uniq || (uniq && uniqCheck var rest))
 letCheck _ _ = False
 
 -- Ditto for "do", except that we have two kinds of syntax:
@@ -79,9 +87,9 @@
 
 doCheck :: [LispVal] -> Bool
 doCheck [] = True
-doCheck ((List [Symbol var, _]):rest) =
+doCheck ((List [Symbol var, _]) : rest) =
   doCheck rest && uniqCheck var rest
-doCheck ((List [Symbol var, _, _]):rest) =
+doCheck ((List [Symbol var, _, _]) : rest) =
   doCheck rest && uniqCheck var rest
 doCheck _ = False
 
@@ -89,94 +97,134 @@
 
 paramsCheck :: [LispVal] -> Bool
 paramsCheck [] = True
-paramsCheck ((Symbol var):rest) =
+paramsCheck (Symbol var : rest) =
   paramsCheck rest && uC var rest
   where uC _ [] = True
-        uC name ((Symbol var2):rest) =
-           if name == var2 then False else uC name rest
-        uC _ _ = progError
+        uC name (Symbol var2 : rmdr) =
+           if name == var2 then False else uC name rmdr
+        uC _ _ = progError "paramsCheck"
 paramsCheck _ = False
 
 -- This is the apply function, the generic
 -- omnipotent thing that does all the work
 
 doApply :: Bool -> String -> [String] -> (Maybe String) -> [LispVal]
-           -> Env -> [[LispVal]] -> Integer -> [LispVal]
-           -> IOThrowsError LispVal
-doApply trace name params varargs body closure dcs ql args =
+           -> Env -> EEnv -> [LispVal] -> Bool -> IOThrowsError LispVal
+doApply trace name params varargs body closure eenv args cflag =
   if num params /= num args && varargs == Nothing
      then errNumArgs (show body) (num params) args
-     else prtTrace >>
-          (liftIO (bindVars closure (zip params args))) >>=
-                bindVarArgs varargs >>= evalBody
+     else do let app = zip params args
+                 ca = head app
+             prtTrace
+             envn <- liftIO (bindVars closure app) >>= bindVarArgs varargs
+             let een = eeNewE eenv envn
+                 eenc = eeNewPE een (ca : eePE een)
+             evalBody (if cflag then eenc else een)
   where remainingArgs = drop (length params) args
         num = toInteger . length
-        evalBody env = mapML (evalLisp env dcs ql) body
+        evalBody ee = mapML (evalLisp ee) body
         bindVarArgs arg env =
           case arg of
                Just argName ->
-                    liftIO (bindVars env [(argName, List (remainingArgs))])
+                    liftIO (bindVars env [(argName, List remainingArgs)])
                Nothing -> return env
         prtTrace =
           if trace
-             then remark ("trace: " ++ name ++ " <- " ++ (show (List args))) >>
-                  return True
+             then remark ("trace: " ++ name ++ " <- " ++ show (List args))
+                  >> return True
              else return False
 
-apply :: [[LispVal]] -> Integer -> LispVal -> [LispVal]
-         -> IOThrowsError LispVal
-apply _ _ (Prim func) args = liftThrows (func args)
-apply _ _ (IOPrim func) args = func args
-apply dcs ql (Func params varargs body closure Nothing _) args =
-  doApply False "" params varargs body closure dcs ql args
-apply dcs ql (Func params varargs body closure (Just name) _) args =
-  doApply True name params varargs body closure dcs ql args
-apply _ _ func _ = throwError (NotFunction "apply got non-function" func)
+apply :: EEnv -> LispVal -> [LispVal] -> IOThrowsError LispVal
+apply _ (Prim func) args = liftThrows (func args)
+apply _ (IOPrim func) args = func args
+apply eenv (Func params varargs body closure Nothing _ cflag) args =
+  doApply False "" params varargs body closure eenv args cflag
+apply eenv (Func params varargs body closure (Just name) _ cflag) args =
+  doApply True name params varargs body closure eenv args cflag
+apply _ func _ = throwError (NotFunction "apply got non-function" func)
 
-makeFunc varargs env params body =
-  return (Func (map show params) varargs body env Nothing False)
-makeNormalFunc = makeFunc Nothing
-makeVarargsFunc = makeFunc . Just . show
+makeFunc, makeMacro ::
+  Monad m => Maybe String -> Env -> [LispVal] -> [LispVal] -> m LispVal
 
+makeFunc varargs env params body =
+  return (Func (map show params) varargs body env Nothing False False)
 makeMacro varargs env params body =
-  return (Func (map show params) varargs body env Nothing True)
+  return (Func (map show params) varargs body env Nothing True False)
+
+makeNormalFunc, makeNormalMacro ::
+  Monad m => Env -> [LispVal] -> [LispVal] -> m LispVal
+
+makeNormalFunc = makeFunc Nothing
 makeNormalMacro = makeMacro Nothing
+
+makeVarargsFunc, makeVarargsMacro ::
+  Monad m => LispVal -> Env -> [LispVal] -> [LispVal] -> m LispVal
+
+makeVarargsFunc = makeFunc . Just . show
 makeVarargsMacro = makeMacro . Just . show
 
+makeContFunc :: Monad m => Env -> [LispVal] -> [LispVal] -> m LispVal
+makeContFunc env params body =
+  return (Func (map show params) Nothing body env Nothing False True)
+
+specialForms :: [String]
 specialForms = ["and", "apply", "begin", "case", "cond", "define",
                 "defmacro", "delay", "do", "eval", "force", "gensym",
                 "guard", "if", "lambda", "let", "let*", "letrec",
                 "letrec*", "load", "or", "quasiquote", "quote", "set!",
                 "unquote", "unquote-splicing", "vector-fill!",
-                "vector-set!", "ext cont", "int cont",
+                "vector-set!", "reset", "shift ",
                 "trace", "dump-bindings"]
 
-isSpecialForm (Symbol s) = seek s specialForms
+isSpecialForm, isInt, isStr, isList, isDL, isVec :: LispVal -> Bool
+
+isSpecialForm (Symbol sym) = seek sym specialForms
   where seek _ [] = False
-        seek s (sf:sfs) = if s == sf then True else seek s sfs
+        seek s (sf:sfs) = (s == sf) || seek s sfs
 isSpecialForm _ = False
 
 isInt (IntNumber _) = True
 isInt _ = False
+
+getInt :: LispVal -> Integer
 getInt (IntNumber n) = n
+getInt _ = progError "getInt"
 
 isStr (String _) = True
 isStr _ = False
+
+getStr :: LispVal -> String
 getStr (String s) = s
+getStr _ = progError "getStr"
 
 isList (List _) = True
 isList _ = False
+
+getList :: LispVal -> [LispVal]
 getList (List l) = l
+getList _ = progError "getList"
 
 isDL (DottedList _ _) = True
 isDL _ = False
+
+getDLh :: LispVal -> [LispVal]
 getDLh (DottedList h _) = h
+getDLh _ = progError "getDLh"
+
+getDLt :: LispVal -> LispVal
 getDLt (DottedList _ t) = t
+getDLt _ = progError "getDLt"
 
 isVec (Vector _ _) = True
 isVec _ = False
+
+getVecL :: LispVal -> Integer
 getVecL (Vector l _) = l
+getVecL _ = progError "getVecL"
+
+getVecV :: LispVal -> DIM.IntMap LispVal
 getVecV (Vector _ v) = v
+getVecV _ = progError "getVecV"
 
 -- This is an internal symbol which temporarily replaces "unquote" and
 -- "unquote-splicing" after these have evaluated the expression(s): evalQQ
@@ -205,7 +253,7 @@
 liftSUnq :: LispVal -> IOThrowsError LispVal
 liftSUnq l@(List ((Symbol sym):vals)) =
   if sym == unq
-     then if (length vals) == 1
+     then if length vals == 1
              then return (head vals)
              else throwError (Default "list unquote form in scalar context")
      else return l
@@ -216,126 +264,109 @@
 -- or an unquote-splicing at the right quote level; these it evaluates via
 -- evalLisp and patches into the tree
 
-evalQQ :: Env -> [[LispVal]] -> Integer -> LispVal -> IOThrowsError LispVal
+evalQQ :: EEnv -> LispVal -> IOThrowsError LispVal
 
 -- "quasiquote", "unquote", and "unquote-splicing" might get evaluated,
 -- depending on quote level
 
-evalQQ env dcs ql (List [Symbol "quasiquote", arg]) =
-  do val <- evalQQ env dcs (ql + 1) arg >>= liftSUnq
+evalQQ eenv (List [Symbol "quasiquote", arg]) =
+  do val <- evalQQ (eeQLIncr eenv) arg >>= liftSUnq
      return (List [Symbol "quasiquote", val])
 
-evalQQ env dcs ql (List (Symbol "unquote" : args)) =
-  if ql == 1
-     then do vals <- mapM (evalLisp env dcs 0) args
-             return (List ((Symbol unq):vals))
-     else do vals <- mapM (evalQQ env dcs (ql - 1)) args
-             return (List ((Symbol "unquote") : (liftLUnq vals)))
+evalQQ eenv (List (Symbol "unquote" : args)) =
+  let een = eeQLDecr eenv
+  in if eeQL eenv == 1
+        then do vals <- mapM (evalLisp een) args
+                return (List (Symbol unq : vals))
+        else do vals <- mapM (evalQQ een) args
+                return (List (Symbol "unquote" : liftLUnq vals))
 
-evalQQ env dcs ql (List (Symbol "unquote-splicing" : args)) =
-  if ql == 1
-     then do vals <- mapM (evalLisp env dcs 0) args
-             if isLL vals
-                then return (List ((Symbol unq):(peel vals)))
-                else throwError (Default ("bad unquote-splicing form: " ++
-                                (show args)))
-     else do vals <- mapM (evalQQ env dcs (ql - 1)) args
-             return (List ((Symbol "unquote-splicing") : (liftLUnq vals)))
+evalQQ eenv (List (Symbol "unquote-splicing" : args)) =
+  let een = eeQLDecr eenv
+  in if eeQL eenv == 1
+        then do vals <- mapM (evalLisp een) args
+                if isLL vals
+                   then return (List (Symbol unq : peel vals))
+                   else throwError (Default ("bad unquote-splicing form: " ++
+                                   show args))
+        else do vals <- mapM (evalQQ een) args
+                return (List (Symbol "unquote-splicing" : liftLUnq vals))
   where isLL [] = True
         isLL ((List _):ls) = isLL ls
         isLL _ = False
         peel [] = []
-        peel ((List l):ls) = l ++ (peel ls)
+        peel ((List l):ls) = l ++ peel ls
+        peel _ = progError "evalQQ/unquote-splicing"
 
 -- lists, dotted-lists, and vectors get traversed
 
-evalQQ env dcs ql (List con) =
-  mapM (evalQQ env dcs ql) con >>= return . List . liftLUnq
+evalQQ eenv (List con) = mapM (evalQQ eenv) con >>= return . List . liftLUnq
 
-evalQQ env dcs ql (DottedList con cab) =
-  do vals <- mapM (evalQQ env dcs ql) con
-     vcab <- evalQQ env dcs ql cab >>= liftSUnq
-     let head = liftLUnq vals
+evalQQ eenv (DottedList con cab) =
+  do vals <- mapM (evalQQ eenv) con
+     vcab <- evalQQ eenv cab >>= liftSUnq
+     let h = liftLUnq vals
      if isList vcab
-        then return (List (head ++ (getList vcab)))
+        then return (List (h ++ getList vcab))
         else if isDL vcab
-                then return (DottedList (head ++ (getDLh vcab)) (getDLt vcab))
-                else return (DottedList head vcab)
+                then return (DottedList (h ++ getDLh vcab) (getDLt vcab))
+                else return (DottedList h vcab)
 
-evalQQ env dcs ql (Vector _ con) =
-  do vals <- mapM (evalQQ env dcs ql) (remkey (DIM.toAscList con))
+evalQQ eenv (Vector _ con) =
+  do vals <- mapM (evalQQ eenv) (remkey (DIM.toAscList con))
      let new = DIM.fromAscList (addkey 0 (liftLUnq vals))
      return (Vector (toInteger (DIM.size new)) new)
   where remkey [] = []
-        remkey ((_, v):vs) = v:(remkey vs)
+        remkey ((_, v) : vs) = v : remkey vs
         addkey _ [] = []
-        addkey n (v:vs) = (n, v):(addkey (n+1) vs)
+        addkey n (v:vs) = (n, v) : addkey (n+1) vs
 
 -- anything else gets returned unchanged
 
-evalQQ _ _ _ val@_ = return val
+evalQQ _ val@_ = return val
 
 -- evalPP is another specialized version of evalLisp: it also walks
 -- the tree and turns the del-cont operators into their internal form,
--- which has a unique identifier and possibly two flags attached. The
--- unique identifier is to be able to identify which is the current
--- hole in an expression if there are several interior operators
--- enclosed within the scope of an exterior operator. The flags are to
--- determine whether or not to attach the two new reset operators
--- during the transformation.
+-- which has a unique identifier attached. The unique identifier is to
+-- be able to identify which is the current hole in an expression if
+-- there are several interior operators enclosed within the scope of
+-- an exterior operator.
 
--- TODO: check shift etc operators for syntactic correctness here?
+-- TODO: check shift operators for syntactic correctness here?
 -- ie, check that the first arg is a symbol and not something else?
 -- probably a good idea...
 
--- TODO: temporarily make this code deal with ALL-CAPS versions of
--- reset et al; otherwise, we break all of the delcont/deltest stuff
-
-evalPP :: Env -> LispVal -> IOThrowsError LispVal
+evalPP :: EEnv -> LispVal -> IOThrowsError LispVal
 
-evalPP env (List ((Symbol sym):arg)) =
-  do argn <- mapM (evalPP env) arg
-     if sym == "RESET"  || sym == "PROMPT"  ||
-        sym == "RESET0" || sym == "PROMPT0" ||
-        sym == "SHIFT"  || sym == "CONTROL" ||
-        sym == "SHIFT0" || sym == "CONTROL0"
-        then do newsym <- transmogrify
-                return (List (newsym ++ argn))
-        else return (List ((Symbol sym) : argn))
-  where transmogrify =
-          do cval <- getVar env contCounter
-             let count = getInt cval
-                 csym = " cont." ++ (show count)
-                 f0 = (sym == "RESET"  || sym == "PROMPT" ||
-                       sym == "RESET0" || sym == "PROMPT0")
-                 f1 = (sym == "SHIFT" || sym == "SHIFT0")
-                 f2 = (sym == "SHIFT" || sym == "CONTROL")
-             do setVar env contCounter (IntNumber (count + 1))
-                return (if f0
-                           then [Symbol "ext cont", Symbol csym]
-                           else [Symbol "int cont", Symbol csym,
-                                 Boolean f1, Boolean f2])
+evalPP eenv (List (Symbol "shift" : arg)) =
+  do let env = eeE eenv
+     argn <- mapM (evalPP eenv) arg
+     cval <- getVar env contCounter
+     let count = getInt cval
+         csym = " cont." ++ show count
+     setVar env contCounter (IntNumber (count + 1))
+     return (List (Symbol "shift " : Symbol csym : argn))
 
-evalPP env (List args) = mapM (evalPP env) args >>= return . List
+evalPP eenv (List args) = mapM (evalPP eenv) args >>= return . List
 
 -- everything else gets returned unchanged
 
-evalPP env val = return val
+evalPP _ val = return val
 
 -- This is the main evaluator
 
-evalLisp :: Env -> [[LispVal]] -> Integer -> LispVal -> IOThrowsError LispVal
+evalLisp :: EEnv -> LispVal -> IOThrowsError LispVal
 
 -- various simple things which evaluate to themselves
 
-evalLisp _ _ _ val@(String _) = return val
-evalLisp _ _ _ val@(IntNumber _) = return val
-evalLisp _ _ _ val@(RatNumber _) = return val
-evalLisp _ _ _ val@(FltNumber _) = return val
-evalLisp _ _ _ val@(Boolean _) = return val
-evalLisp _ _ _ val@(Char _) = return val
-evalLisp _ _ _ (List []) = return (List [])
-evalLisp env _ _ (Symbol id) = getVar env id
+evalLisp _ val@(String _) = return val
+evalLisp _ val@(IntNumber _) = return val
+evalLisp _ val@(RatNumber _) = return val
+evalLisp _ val@(FltNumber _) = return val
+evalLisp _ val@(Boolean _) = return val
+evalLisp _ val@(Char _) = return val
+evalLisp _ (List []) = return (List [])
+evalLisp eenv (Symbol ident) = getVar (eeE eenv) ident
 
 -- Special forms must go here, before the generic (function : args) stuff
 
@@ -345,12 +376,13 @@
 -- convenient to have it here; otherwise, we have to do all sorts of
 -- twisting to make it all work.
 
-evalLisp env dcs ql (List (Symbol "apply" : function : args)) =
-  do func <- evalLisp env dcs ql function
-     argVals <- mapM (evalLisp env dcs ql) args
+evalLisp eenv (List (Symbol "apply" : fn : args)) =
+  do func <- evalLisp eenv fn
+     argVals <- mapM (evalLisp eenv) args
      appp (func:argVals)
-  where appp [func, List args] = apply dcs ql func args
-        appp (func : args) = apply dcs ql func args
+  where appp [f, List as] = apply eenv f as
+        appp (f : as) = apply eenv f as
+        appp _ = progError "evalLisp/apply"
 
 -- TODO: this is not a special form according to R6RS; the only reason
 -- I put it here is because evalLisp wants an environment, and that's
@@ -363,10 +395,8 @@
 -- move this into the libraries... I'd just have to provide access to
 -- the (or a) top-level environment.
 
-evalLisp env dcs ql (List (Symbol "eval" : args)) =
-  mapM (evalPP env) args >>=
-  mapM (evalLisp env dcs ql) >>=
-  mapML (evalLisp env dcs ql)
+evalLisp eenv (List (Symbol "eval" : args)) =
+  mapM (evalPP eenv) args >>= mapM (evalLisp eenv) >>= mapML (evalLisp eenv)
 
 -- TODO: This is also not a special form according to R6RS; I think I
 -- could also make it a regular function, but it has the same issues
@@ -375,294 +405,305 @@
 -- wants to (or should be able to) call (load) from within some
 -- function and modify the environment seen within that function.
 
-evalLisp env dcs ql (List [Symbol "load", arg]) =
-  do fname <- evalLisp env dcs ql arg
+evalLisp eenv (List [Symbol "load", arg]) =
+  do fname <- evalLisp eenv arg
      if isStr fname
         then loadFile (getStr fname) >>=
-             mapM (evalPP env) >>=
-             mapML (evalLisp env dcs ql)
+             mapM (evalPP eenv) >>= mapML (evalLisp eenv)
         else throwError (Default ("bad load form: " ++
-                                  (show fname) ++ " is not a string"))
+                                  show fname ++ " is not a string"))
 
-evalLisp env dcs ql (List (Symbol "begin" : args)) =
-  mapML (evalLisp env dcs ql) args
+evalLisp eenv (List (Symbol "begin" : args)) = mapML (evalLisp eenv) args
 
-evalLisp _ _ _ (List [Symbol "quote", val]) = return val
+evalLisp _ (List [Symbol "quote", val]) = return val
 
-evalLisp env dcs ql (List [Symbol "quasiquote", val]) =
-  evalQQ env dcs (ql + 1) val >>= liftSUnq
+evalLisp eenv (List [Symbol "quasiquote", val]) =
+  evalQQ (eeQLIncr eenv) val >>= liftSUnq
 
-evalLisp _ _ _ (List (Symbol "unquote" : args)) =
-  throwError (Default ("naked unquote form: " ++ (show args)))
+evalLisp _ (List (Symbol "unquote" : args)) =
+  throwError (Default ("naked unquote form: " ++ show args))
 
-evalLisp _ _ _ (List (Symbol "unquote-splicing" : args)) =
-  throwError (Default ("naked unquote-splicing form: " ++ (show args)))
+evalLisp _ (List (Symbol "unquote-splicing" : args)) =
+  throwError (Default ("naked unquote-splicing form: " ++ show args))
 
-evalLisp env dcs ql (List [Symbol "set!", Symbol var, val]) =
-  evalLisp env dcs ql val >>= setVar env var
+evalLisp eenv (List [Symbol "set!", Symbol var, val]) =
+  evalLisp eenv val >>= setVar (eeE eenv) var
 
-evalLisp env dcs ql (List [Symbol "vector-set!", Symbol var, indx, obj]) =
-  do vec <- evalLisp env dcs ql (Symbol var)
+evalLisp eenv (List [Symbol "vector-set!", Symbol var, indx, obj]) =
+  do vec <- evalLisp eenv (Symbol var)
      if isVec vec
-        then do lk <- evalLisp env dcs ql indx
+        then do lk <- evalLisp eenv indx
                 let l = getVecL vec
                     k = getInt lk
-                if ((isInt lk) && k >= 0 && k < l)
-                   then do val <- evalLisp env dcs ql obj
-                           setVar env var (Vector l
+                if isInt lk && k >= 0 && k < l
+                   then do val <- evalLisp eenv obj
+                           setVar (eeE eenv) var (Vector l
                              (DIM.insert (fromInteger k) val (getVecV vec)))
                    else throwError (VectorBounds l lk)
         else throwError (Default ("bad vector-set! form: " ++
-                                  (show var) ++ " is not a vector"))
+                                  show var ++ " is not a vector"))
 
-evalLisp env dcs ql (List [Symbol "vector-fill!", Symbol var, obj]) =
-  do vec <- evalLisp env dcs ql (Symbol var)
+evalLisp eenv (List [Symbol "vector-fill!", Symbol var, obj]) =
+  do vec <- evalLisp eenv (Symbol var)
      if isVec vec
-        then do val <- evalLisp env dcs ql obj
+        then do val <- evalLisp eenv obj
                 let n = getVecL vec
-                setVar env var (Vector n (DIM.fromAscList
+                setVar (eeE eenv) var (Vector n (DIM.fromAscList
                   (addkey val (fromInteger n))))
         else throwError (Default ("bad vector-fill! form: " ++
-                                  (show var) ++ " is not a vector"))
+                                  show var ++ " is not a vector"))
   where addkey _ 0 = []
-        addkey v n = ((n-1), v):(addkey v (n-1))
+        addkey v n = ((n-1), v) : addkey v (n-1)
 
-evalLisp env dcs ql (List [Symbol "vector-resize!", Symbol var, obj]) =
-  do vec <- evalLisp env dcs ql (Symbol var)
+evalLisp eenv (List [Symbol "vector-resize!", Symbol var, obj]) =
+  do vec <- evalLisp eenv (Symbol var)
      if isVec vec
-        then do lk <- evalLisp env dcs ql obj
+        then do lk <- evalLisp eenv obj
                 let l = getVecL vec
                     k = getInt lk
-                if (isInt lk) && (k > 0)
+                if isInt lk && k > 0
                    then do let new = if k < l
-                                        then rem (getVecV vec) l k
+                                        then rmv (getVecV vec) l k
                                         else add (getVecV vec) k l
-                           setVar env var (Vector k new)
+                           setVar (eeE eenv) var (Vector k new)
                    else throwError (Default ("bad vector-resize! size: " ++
-                                             (show k)))
+                                             show k))
         else throwError (Default ("bad vector-resize! form: " ++
-                                  (show var) ++ " is not a vector"))
-  where rem vec h l =
+                                  show var ++ " is not a vector"))
+  where rmv vec h l =
           if h == l
              then vec
-             else rem (DIM.delete (fromInteger l) vec) h (l + 1)
+             else rmv (DIM.delete (fromInteger l) vec) h (l + 1)
         add vec h l =
           if h == l
              then vec
              else add (DIM.insert (fromInteger l) lispFalse vec) h (l + 1)
 
-evalLisp env dcs ql (List [Symbol "define", Symbol var, val]) =
-  do defineVar env var lispFalse
-     evalLisp env dcs ql val >>= setVar env var
-evalLisp env _ _ (List [Symbol "define", Symbol var]) =
-  defineVar env var lispFalse
-evalLisp env dcs _
+evalLisp eenv (List [Symbol "define", Symbol var, val]) =
+  do let env = eeE eenv
+     defineVar env var lispFalse
+     evalLisp eenv val >>= setVar env var
+evalLisp eenv (List [Symbol "define", Symbol var]) =
+  defineVar (eeE eenv) var lispFalse
+evalLisp (EEnv env _ _ _)
     (List (Symbol "define" : List (Symbol var : params) : body)) =
   if paramsCheck params
      then do defineVar env var lispFalse
              makeNormalFunc env params body >>= setVar env var
      else errBadForm "define" params
-evalLisp env dcs _ (List (Symbol "define" :
+evalLisp (EEnv env _ _ _) (List (Symbol "define" :
     DottedList (Symbol var : params) varargs : body)) =
   if paramsCheck (params ++ [varargs])
      then do defineVar env var lispFalse
              makeVarargsFunc varargs env params body >>= setVar env var
      else errBadForm "define" [DottedList params varargs]
 
-evalLisp env dcs _
+evalLisp (EEnv env _ _ _)
     (List (Symbol "defmacro" : List (Symbol var : params) : body)) =
   if paramsCheck params
      then do defineVar env var lispFalse
              makeNormalMacro env params body >>= setVar env var
      else errBadForm "defmacro" params
-evalLisp env dcs _ (List (Symbol "defmacro" :
+evalLisp (EEnv env _ _ _) (List (Symbol "defmacro" :
     DottedList (Symbol var : params) varargs : body)) =
   if paramsCheck (params ++ [varargs])
      then do defineVar env var lispFalse
              makeVarargsMacro varargs env params body >>= setVar env var
      else errBadForm "defmacro" [DottedList params varargs]
 
-evalLisp env dcs _ (List (Symbol "lambda" : List params : body)) =
+evalLisp eenv (List (Symbol "lambda" : List params : body)) =
   if paramsCheck params
-     then makeNormalFunc env params body
+     then makeNormalFunc (eeE eenv) params body
      else errBadForm "lambda" params
-evalLisp env dcs _
+evalLisp eenv
     (List (Symbol "lambda" : DottedList params varargs : body)) =
   if paramsCheck (params ++ [varargs])
-     then makeVarargsFunc varargs env params body
+     then makeVarargsFunc varargs (eeE eenv) params body
      else errBadForm "lambda" [DottedList params varargs]
-evalLisp env dcs _ (List (Symbol "lambda" : varargs@(Symbol _) : body)) =
-  makeVarargsFunc varargs env [] body
+evalLisp eenv (List (Symbol "lambda" : varargs@(Symbol _) : body)) =
+  makeVarargsFunc varargs (eeE eenv) [] body
 
-evalLisp env dcs ql (List [Symbol "if", pred, tcase, fcase]) =
-  do result <- evalLisp env dcs ql pred
+evalLisp eenv (List [Symbol "if", pr, tcase, fcase]) =
+  do result <- evalLisp eenv pr
      case result of
-          Boolean False -> evalLisp env dcs ql fcase
-          _ -> evalLisp env dcs ql tcase
-evalLisp env dcs ql (List [Symbol "if", pred, tcase]) =
-  do result <- evalLisp env dcs ql pred
+          Boolean False -> evalLisp eenv fcase
+          _ -> evalLisp eenv tcase
+evalLisp eenv (List [Symbol "if", pr, tcase]) =
+  do result <- evalLisp eenv pr
      case result of
           Boolean False -> return lispFalse
-          _ -> evalLisp env dcs ql tcase
+          _ -> evalLisp eenv tcase
 
-evalLisp env dcs ql (List (Symbol "and" : args)) = eva env args lispTrue
+evalLisp eenv (List (Symbol "and" : args)) = eva (eeE eenv) args lispTrue
   where eva _ [] ret = return ret
         eva env (t:ts) _ =
-          do result <- evalLisp env dcs ql t
+          do result <- evalLisp eenv t
              case result of
                   Boolean False -> return lispFalse
                   _ -> eva env ts result
 
-evalLisp env dcs ql (List (Symbol "or" : args)) = evo env args lispFalse
+evalLisp eenv (List (Symbol "or" : args)) = evo (eeE eenv) args lispFalse
   where evo _ [] ret = return ret
         evo env (t:ts) _ =
-          do result <- evalLisp env dcs ql t
+          do result <- evalLisp eenv t
              case result of
                   Boolean False -> evo env ts result
                   _ -> return result
 
-evalLisp _ _ _ (List [Symbol "cond"]) = return lispFalse
-evalLisp env dcs ql (List (Symbol "cond" : args)) =
-  if foldl1 (&&) (map isList args) == False
-     then errTypeMismatch "cond" "cond-clauses" (String (show args))
-     else evc env args
+evalLisp _ (List [Symbol "cond"]) = return lispFalse
+evalLisp eenv (List (Symbol "cond" : args)) =
+  if all isList args
+     then evc (eeE eenv) args
+     else errTypeMismatch "cond" "cond-clauses" (String (show args))
   where evc _ [] = return lispFalse
         evc env (cl:cls) = do (tst,val) <- evc_clause env cl
                               if tst then return val else evc env cls
-        evc_clause env (List (Symbol "else" : args)) =
-          do ret <- mapML (evalLisp env dcs ql) args
+        evc_clause _ (List (Symbol "else" : as)) =
+          do ret <- mapML (evalLisp eenv) as
              return (True, ret)
-        evc_clause env (List (pred : args)) =
-          do tst <- evalLisp env dcs ql pred
+        evc_clause env (List (pr : as)) =
+          do tst <- evalLisp eenv pr
              case tst of
                   Boolean False -> return (False, lispFalse)
-                  _ -> do ret <- if isArrow args
-                                    then evcArrow env args tst
-                                    else mapML (evalLisp env dcs ql) args
+                  _ -> do ret <- if isArrow as
+                                    then evcArrow env as tst
+                                    else mapML (evalLisp eenv) as
                           return (True, ret)
         evc_clause _ _ = return (False, lispFalse)
         isArrow [Symbol "=>", _] = True
         isArrow _ = False
         evcArrow env [Symbol "=>", proc] val =
-          evalLisp env dcs ql proc >>= (flip (apply dcs ql)) [val]
+          let een = eeNewE eenv env
+          in evalLisp een proc >>= flip (apply een) [val]
+        evcArrow _ _ _ = progError "evalLisp/cond/evcArrow"
 
-evalLisp env dcs ql (List (Symbol "let" : List params : body)) =
+evalLisp eenv (List (Symbol "let" : List params : body)) =
   if letCheck True params
-     then do func <- makeNormalFunc env (map exn params) body
-             argVals <- mapM (evalLisp env dcs ql) (map exv params)
-             apply dcs ql func argVals
+     then do func <- makeNormalFunc (eeE eenv) (map exn params) body
+             mapM (evalLisp eenv . exv) params >>= apply eenv func
      else errBadForm "let" params
-    where exn (List [Symbol var, _]) = Symbol var
-          exv (List [Symbol _, val]) = val
+  where exn (List [Symbol var, _]) = Symbol var
+        exn _ = progError "evalLisp/let/exn1"
+        exv (List [Symbol _, val]) = val
+        exv _ = progError "evalLisp/let/exv1"
 
-evalLisp env dcs ql
+evalLisp eenv
     (List (Symbol "let" : Symbol lname : List params : body)) =
   if letCheck True params
-     then do envn <- liftIO (bindVars env [(lname, lispFalse)])
+     then do envn <- liftIO (bindVars (eeE eenv) [(lname, lispFalse)])
              func <- makeNormalFunc envn (map exn params) body
              setVar envn lname func
-             argVals <- mapM (evalLisp env dcs ql) (map exv params)
-             apply dcs ql func argVals
+             mapM (evalLisp eenv . exv) params >>= apply eenv func
      else errBadForm "named-let" params
-    where exn (List [Symbol var, _]) = Symbol var
-          exv (List [Symbol _, val]) = val
+  where exn (List [Symbol var, _]) = Symbol var
+        exn _ = progError "evalLisp/let/exn2"
+        exv (List [Symbol _, val]) = val
+        exv _ = progError "evalLisp/let/exv2"
 
-evalLisp env dcs ql (List (Symbol "let*" : List params : body)) =
+evalLisp eenv (List (Symbol "let*" : List params : body)) =
   if letCheck False params
-     then dols params body env
+     then dols params body (eeE eenv)
      else errBadForm "let*" params
-  where dols [] body env = mapML (evalLisp env dcs ql) body
-        dols (p:ps) body env =
-             do val <- evalLisp env dcs ql (exv p)
-                (liftIO (bindVars env [(exn p, val)])) >>= (dols ps body)
+  where dols [] b env = mapML (evalLisp (eeNewE eenv env)) b
+        dols (p:ps) b env =
+             do val <- evalLisp (eeNewE eenv env) (exv p)
+                liftIO (bindVars env [(exn p, val)]) >>= dols ps b
         exn (List [Symbol var, _]) = var
+        exn _ = progError "evalLisp/let*/exn"
         exv (List [Symbol _, val]) = val
+        exv _ = progError "evalLisp/let*/exv"
 
-evalLisp env dcs ql (List (Symbol "letrec" : List params : body)) =
+evalLisp eenv (List (Symbol "letrec" : List params : body)) =
   if letCheck True params
-     then dolr params body env
+     then dolr params body (eeE eenv)
      else errBadForm "letrec" params
-  where dolr params body env =
-          do let varn = map exn params
+  where dolr ps b env =
+          do let varn = map exn ps
              envn <- liftIO (bindVars env varn)
-             varv <- mapM (evalLisp envn dcs ql) (map exv params)
-             mapM (doSet envn) (repl varn varv) >>
-                  mapML (evalLisp envn dcs ql) body
+             let een = eeNewE eenv envn
+             varv <- mapM (evalLisp een . exv) ps
+             mapM_ (doSet envn) (repl varn varv) >> mapML (evalLisp een) b
         exn (List [Symbol var, _]) = (var, lispFalse)
+        exn _ = progError "evalLisp/letrec/exn"
         exv (List [Symbol _, val]) = val
+        exv _ = progError "evalLisp/letrec/exv"
         repl [] [] = []
-        repl ((n, lispFalse):ns) (v:vs) = (n, v):(repl ns vs)
+-- TODO: fix this! it's infelicitous... would prefer to not know
+-- what lispFalse looks like on the inside
+        repl ((n, Boolean False):ns) (v:vs) = (n, v) : repl ns vs
+        repl _ _ = progError "evalLisp/letrec/repl"
         doSet env (n,v) = setVar env n v
 
-evalLisp env dcs ql (List (Symbol "letrec*" : List params : body)) =
+evalLisp eenv (List (Symbol "letrec*" : List params : body)) =
   if letCheck False params
-     then dolr params body env
+     then dolr params body (eeE eenv)
      else errBadForm "letrec*" params
-  where dolr params body env =
-          do let varn = map exn params
+  where dolr ps b env =
+          do let varn = map exn ps
              envn <- liftIO (bindVars env varn)
-             mapM (evSet envn) params >>
-                  mapML (evalLisp envn dcs ql) body
+             mapM_ (evSet envn) ps >>
+                  mapML (evalLisp (eeNewE eenv envn)) b
         exn (List [Symbol var, _]) = (var, lispFalse)
+        exn _ = progError "evalLisp/letrec*/exn"
         evSet env (List [Symbol var, val]) =
-              evalLisp env dcs ql val >>= setVar env var
+              evalLisp (eeNewE eenv env) val >>= setVar env var
+        evSet _ _ = progError "evalLisp/letrec*/evSet"
 
-evalLisp _ _ _ (List [Symbol "case"]) = return lispFalse
-evalLisp env dcs ql (List (Symbol "case" : key : args)) =
-  if (isNull args) || (foldl1 (&&) (map isLL args) == False)
-     then errTypeMismatch "case" "case-clauses" (String (show args))
-     else evalLisp env dcs ql key >>= evc env args
-  where isNull [] = True
-        isNull _ = False
-        isLL (List (List _ : _)) = True
+evalLisp _ (List [Symbol "case"]) = return lispFalse
+evalLisp eenv (List (Symbol "case" : k : as)) =
+  if null as || not (all isLL as)
+     then errTypeMismatch "case" "case-clauses" (String (show as))
+     else evalLisp eenv k >>= evc (eeE eenv) as
+  where isLL (List (List _ : _)) = True
         isLL (List (Symbol "else" : _)) = True
         isLL _ = False
         evc _ [] _ = return lispFalse
-        evc env (cl:cls) key = do (tst,val) <- evc_clause env cl key
-                                  if tst then return val else evc env cls key
+        evc env (cl:cls) k1 = do (tst,val) <- evc_clause env cl k1
+                                 if tst then return val else evc env cls k1
         evc_clause env (List (Symbol "else" : args)) _ =
-          do ret <- mapML (evalLisp env dcs ql) args
+          do ret <- mapML (evalLisp (eeNewE eenv env)) args
              return (True, ret)
-        evc_clause env (List (List vals : args)) key =
-          if valMatch key vals
-             then do ret <- mapML (evalLisp env dcs ql) args
+        evc_clause env (List (List vals : args)) k1 =
+          if valMatch k1 vals
+             then do ret <- mapML (evalLisp (eeNewE eenv env)) args
                      return (True, ret)
              else return (False, lispFalse)
         evc_clause _ _ _ = return (False, lispFalse)
-        valMatch key (v:vs) = if Library.eqv [key, v]
-                                 then True
-                                 else (valMatch key vs)
+        valMatch k1 (v:vs) = Library.eqv [k1, v] || valMatch k1 vs
         valMatch _ [] = False
 
-evalLisp env dcs ql
+evalLisp eenv
     (List (Symbol "guard" : List (Symbol var : clauses) : body)) =
-  if foldl (&&) True (map isList clauses) == False
-     then errTypeMismatch "guard" "error-clauses" (String (show clauses))
-     else catchError (mapML (evalLisp env dcs ql) body)
+  if all isList clauses
+     then catchError (mapML (evalLisp eenv) body)
                      (\err -> do let errval = unpackErr err
-                                 liftIO (bindVars env [(var, errval)]) >>=
-                                   evc err clauses)
+                                 liftIO (bindVars (eeE eenv) [(var, errval)])
+                                   >>= evc err clauses)
+     else errTypeMismatch "guard" "error-clauses" (String (show clauses))
   where unpackErr (UserException val) = val
         unpackErr err = String (show err)
         evc err [] _ = throwError err
         evc err (cl:cls) env = do (tst,val) <- evc_clause env cl
                                   if tst then return val else evc err cls env
         evc_clause env (List (Symbol "else" : args)) =
-          do ret <- mapML (evalLisp env dcs ql) args
+          do ret <- mapML (evalLisp (eeNewE eenv env)) args
              return (True, ret)
-        evc_clause env (List (pred : args)) =
-          do tst <- evalLisp env dcs ql pred
+        evc_clause env (List (pr : args)) =
+          do let een = eeNewE eenv env
+             tst <- evalLisp een pr
              case tst of
                   Boolean False -> return (False, lispFalse)
                   _ -> do ret <- if isArrow args
                                     then evcArrow env args tst
-                                    else mapML (evalLisp env dcs ql) args
+                                    else mapML (evalLisp een) args
                           return (True, ret)
         evc_clause _ _ = return (False, lispFalse)
         isArrow [Symbol "=>", _] = True
         isArrow _ = False
         evcArrow env [Symbol "=>", proc] val =
-          evalLisp env dcs ql proc >>= (flip (apply dcs ql)) [val]
+          let een = eeNewE eenv env
+          in evalLisp een proc >>= flip (apply een) [val]
+        evcArrow _ _ _ = progError "evalLisp/guard/evcArrow"
 
 -- This creates an internal variable for each delay object where its value
 -- will be stored once it is forced. We avoid collisions with any symbols
@@ -670,14 +711,15 @@
 -- space: the parser won't let such strings through as symbols, so we are
 -- never in the situation where something might clash.
 
-evalLisp env _ _ (List [Symbol "delay", val]) =
-  do dval <- getVar env delayCounter
+evalLisp eenv (List [Symbol "delay", val]) =
+  do let env = eeE eenv
+     dval <- getVar env delayCounter
      let count = getInt dval
      do setVar env delayCounter (IntNumber (count + 1))
-        return (Delay val env (" delay." ++ (show count)))
+        return (Delay val env (" delay." ++ show count))
 
-evalLisp envc dcs ql (List [Symbol "force", val]) =
-  do vali <- evalLisp envc dcs ql val
+evalLisp eenv (List [Symbol "force", val]) =
+  do vali <- evalLisp eenv val
      if isDelay vali
         then do let (env, tag) = getTag vali
                 alreadyDef <- liftIO (isBound env tag)
@@ -688,84 +730,92 @@
   where isDelay (Delay _ _ _) = True
         isDelay _ = False
         getTag (Delay _ env tag) = (env, tag)
-        forceEval (Delay obj env _) = evalLisp env dcs ql obj
+        getTag _ = progError "evalLisp/getTag"
+        forceEval (Delay obj env _) = evalLisp (eeNewE eenv env) obj
+        forceEval _ = progError "evalLisp/forceEval"
 
-evalLisp env dcs ql (List (Symbol "do" : List params : List test : body)) =
+evalLisp eenv (List (Symbol "do" : List params : List test : body)) =
   if doCheck params
      then do let names = map exn params
                  steps = map exs params
-             inits <- mapM (evalLisp env dcs ql) (map exi params)
-             envn <- liftIO (bindVars env (zip names inits))
+             inits <- mapM (evalLisp eenv . exi) params
+             envn <- liftIO (bindVars (eeE eenv) (zip names inits))
              doloop envn names test steps
      else errBadForm "do" params
   where exn (List [Symbol var, _]) = var
         exn (List [Symbol var, _, _]) = var
-        exi (List [Symbol _, init]) = init
-        exi (List [Symbol _, init, _]) = init
+        exn _ = progError "evalLisp/do/exn"
+        exi (List [Symbol _, ini]) = ini
+        exi (List [Symbol _, ini, _]) = ini
+        exi _ = progError "evalLisp/do/exi"
         exs (List [Symbol var, _]) = Symbol var
         exs (List [Symbol _, _, step]) = step
+        exs _ = progError "evalLisp/do/exs"
         doSet env (n,v) = setVar env n v
-        doloop env names (test:rets) steps =
-          do tval <- evalLisp env dcs ql test
+        doloop env names (tst:rets) steps =
+          do let een = eeNewE eenv env
+             tval <- evalLisp een tst
              if isTrue tval
-                then mapML (evalLisp env dcs ql) rets
-                else do mapM (evalLisp env dcs ql) body
-                        svals <- mapM (evalLisp env dcs ql) steps
-                        mapM (doSet env) (zip names svals)
-                        doloop env names (test:rets) steps
+                then mapML (evalLisp een) rets
+                else do mapM_ (evalLisp een) body
+                        svals <- mapM (evalLisp een) steps
+                        mapM_ (doSet env) (zip names svals)
+                        doloop env names (tst:rets) steps
+        doloop _ _ [] _ = progError "evalLisp/do/doloop"
 
 -- This creates a new guaranteed-never-before-used symbol (and one which
 -- the user can't enter, so guaranteed no past present or future clashes).
 
-evalLisp env _ _ (List [Symbol "gensym"]) =
+evalLisp (EEnv env _ _ _) (List [Symbol "gensym"]) =
   do sval <- getVar env symbolCounter
      let count = getInt sval
      do setVar env symbolCounter (IntNumber (count + 1))
-        return (Symbol (" symbol." ++ (show count)))
+        return (Symbol (" symbol." ++ show count))
 
--- Delimited continuations -- two new special forms:
--- (ext cont id expr ...) which is the translation of reset etc
--- (int cont id flag1 flag2 expr ...) which is the translation of shift etc
--- NOTE! 'int cont' and 'ext cont' are each a single symbol, with a
--- space in the middle: this prevents the user from entering these directly
--- ... well, not really, but it makes it enough harder that it has to be
--- done intentionally: take an expression apart, rebuild it with a macro,
--- and attempt to process that. If you do that, you deserve what you get.
+-- Delimited continuations -- two new special forms: (reset expr ...)
+-- and (shift  id fname expr ...) which is the translation of shift
 
--- TODO: we may need to add individual ids to the DelCont... this is part
--- of delcont.scm, although I don't quite understand it
+-- NOTE! 'shift ' is a single symbol, with a space at the end; this makes it
+-- harder for the user to enter it directly (but not impossible: generate a
+-- quoted expression like '(reset (shift f #t)), then take the result apart
+-- to get the desired symbols... if you do this, you deserve what you get).
 
-evalLisp env dcs ql (List ((Symbol "ext cont"):(Symbol id):args)) =
-  catchError (mapML (evalLisp env (args:dcs) ql) args)
-             (\val -> getVal val)
+evalLisp eenv@(EEnv _ _ dcs _) (List (Symbol "reset" : as)) =
+  catchError (mapML (evalLisp (eeNewDC eenv (as:dcs))) as) getVal
   where getVal (DelCont val) = return val
         getVal err = throwError err
 
-evalLisp env [] ql a@(List ((Symbol "int cont"):
-        (Symbol id):(Boolean f1):(Boolean f2):(Symbol fn):args)) =
+evalLisp (EEnv _ _ [] _)
+    a@(List (Symbol "shift " : Symbol _ : Symbol _ : _)) =
   throwError (BadSpecial "naked internal delcont form" a)
 
 -- TODO: does the isCont test need to be made more discriminating?
 -- check if it could perhaps fail with nested or multiple calls to the
 -- continuation function
 
--- TODO: look into why some of the reset0/prompt/prompt0 examples are failing
+evalLisp eenv (List (Symbol "shift " : Symbol cid : Symbol fn : as)) =
+  do let env = eeE eenv
+         isCont = lookup cid (eePE eenv)
+     case isCont of
+          Just val -> return val
+          Nothing -> do let cbody = [List (Symbol "reset" :
+                                           head (eeDC eenv))]
+                            ebody = [List (Symbol "reset" : as)]
+                        func <- makeContFunc env [Symbol cid] cbody
+                        envn <- liftIO (bindVars env [(fn, func)])
+                        mapML (evalLisp (eeNewE eenv envn)) ebody
+                          >>= throwError . DelCont
 
-evalLisp env dcs ql (List ((Symbol "int cont"):
-        (Symbol id):(Boolean f1):(Boolean f2):(Symbol fn):args)) =
-  do isCont <- liftIO (isBound env id)
+{-
      if isCont
-        then (getVar env id) >>= return
-        else do cbody <- wrapit f1 (head dcs)
-                func <- makeNormalFunc env [Symbol id] cbody
+        then (getVar env cid) >>= return
+        else do let cbody = [List ([Symbol "reset"] ++ (head (eeDC eenv)))]
+                    ebody = [List ([Symbol "reset"] ++ as)]
+                func <- makeContFunc env [Symbol cid] cbody
                 envn <- liftIO (bindVars env [(fn, func)])
-                ebody <- wrapit f2 args
-                mapML (evalLisp envn dcs ql) ebody >>= throwError . DelCont
-  where wrapit flag exs =
-          if flag
-             then do wrap <- evalPP env (List ((Symbol "RESET"):[lispFalse]))
-                     return [List ((take 2 (getList wrap)) ++ exs)]
-             else return exs
+                mapML (evalLisp (eeNewE eenv envn)) ebody
+                  >>= throwError . DelCont
+-}
 
 -- This is not an R6RS special form, but it is a haskeem one: it needs
 -- to be, because we don't want to evaluate the function name, and we
@@ -780,75 +830,75 @@
 -- expression which evaluates to the symbol to trace, because we want
 -- to have a name: var is what gets used. Consider relaxing this?
 
-evalLisp env dcs ql (List [Symbol "trace", Symbol var, sw]) =
+evalLisp eenv (List [Symbol "trace", Symbol var, sw]) =
   if isSpecialForm (Symbol var)
      then throwError (Default "can't trace special forms")
-     else do val <- evalLisp env dcs ql (Symbol var)
-             swval <- evalLisp env dcs ql sw
+     else do val <- evalLisp eenv (Symbol var)
+             swval <- evalLisp eenv sw
+             let env = eeE eenv
              if isPr val
                 then throwError (Default "can't trace primitives")
-                else if (isF val)
+                else if isF val
 -- TODO: this can be cleaned up a bit more... doit!
-                        then if (isTrue swval)
-                                then (remark ("trace " ++ var ++ " on")) >>
+                        then if isTrue swval
+                                then remark ("trace " ++ var ++ " on") >>
                                      setVar env var (trOn var val) >>
                                      return lispTrue
-                                else (remark ("trace " ++ var ++ " off")) >>
+                                else remark ("trace " ++ var ++ " off") >>
                                      setVar env var (trOff val) >>
                                      return lispFalse
-                        else errBadForm "trace" ((Symbol var):[sw])
+                        else errBadForm "trace" (Symbol var : [sw])
   where isPr (Prim _) = True
         isPr (IOPrim _) = True
         isPr _ = False
-        isF (Func _ _ _ _ _ _) = True
+        isF (Func _ _ _ _ _ _ _) = True
         isF _ = False
-        trOn name (Func params varargs body closure _ mac) =
-              (Func params varargs body closure (Just name) mac)
-        trOn _ _ = progError
-        trOff (Func params varargs body closure _ mac) =
-              (Func params varargs body closure Nothing mac)
-        trOff _ = progError
+        trOn name (Func params varargs body closure _ mac cont) =
+              Func params varargs body closure (Just name) mac cont
+        trOn _ _ = progError "evalLisp/trace/trOn"
+        trOff (Func params varargs body closure _ mac cont) =
+              Func params varargs body closure Nothing mac cont
+        trOff _ = progError "evalLisp/trace/trOff"
 
 -- This is also not an R6RS special form, but a haskeem one: it needs
 -- to be, because we want the ability to show the current environment
 -- rather than just the top-level one
 
-evalLisp env _ _ (List [Symbol "dump-bindings"]) = dumpEnv env stderr
-evalLisp env dcs ql (List [Symbol "dump-bindings", val]) =
-  do vali <- evalLisp env dcs ql val
+evalLisp eenv (List [Symbol "dump-bindings"]) = dumpEnv (eeE eenv) stderr []
+evalLisp eenv (List [Symbol "dump-bindings", val]) =
+  do vali <- evalLisp eenv val
      if isPort vali
-        then dumpEnv env (getPort vali)
+        then dumpEnv (eeE eenv) (getPort vali) []
         else errBadForm "dump-bindings" [val]
   where isPort (Port _) = True
         isPort _ = False
         getPort (Port p) = p
-        getPort _ = progError
+        getPort _ = progError "evalLisp/dump-bindings"
 
--- The generic (function : args) stuff; also macro expansion stuff
+-- The generic (function : as) stuff; also macro expansion stuff
 -- For macro expansion, we evaluate once to get syntax back from the
 -- macro, that's the "evalLisp env dcs ql function", but then we change
 -- the environment to evaluate that syntax in the caller's environment.
 
-evalLisp env dcs ql (List (function : args)) =
+evalLisp eenv (List (function : as)) =
   if isSpecialForm function
      then throwError (BadSpecial "bad syntax for special form" function)
-     else do func <- evalLisp env dcs ql function
+     else do func <- evalLisp eenv function
              if isM func
-                then apply dcs ql (chEnv func env) args >>=
-                     prtTrace (isT func) >>=
-                     evalPP env >>=
-                     evalLisp env dcs ql
-                else mapM (evalLisp env dcs ql) args >>= apply dcs ql func
-  where isM (Func _ _ _ _ _ mac) = mac
+                then apply eenv (chEnv func (eeE eenv)) as >>=
+                     prtTrace (isT func) >>= evalPP eenv >>= evalLisp eenv
+                else mapM (evalLisp eenv) as >>= apply eenv func
+  where isM (Func _ _ _ _ _ mac _) = mac
         isM _ = False
-        isT (Func _ _ _ _ (Just _) _) = True
+        isT (Func _ _ _ _ (Just _) _ _) = True
         isT _ = False
-        chEnv (Func pars vars bod envo name mac) envn =
-          Func pars vars bod envn name mac
+        chEnv (Func pars vars bod _ name mac cont) envn =
+          Func pars vars bod envn name mac cont
+        chEnv _ _ = progError "evalLisp/generic-function"
         prtTrace trace vals =
           if trace
-             then remark ("   ->  " ++ (show vals)) >> return vals
+             then remark ("   ->  " ++ show vals) >> return vals
              else return vals
 
-evalLisp _ _ _ badForm =
+evalLisp _ badForm =
   throwError (BadSpecial "Unrecognized special form" badForm)
diff --git a/Library.hs b/Library.hs
--- a/Library.hs
+++ b/Library.hs
@@ -18,8 +18,10 @@
 along with haskeem; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
-$Id: library.hs,v 1.39 2009-08-06 05:05:15 uwe Exp $ -}
+$Id: library.hs,v 1.43 2010-01-18 00:08:49 uwe Exp $ -}
 
+{-# LANGUAGE FlexibleContexts #-}
+
 module Library (primitiveBindings, delayCounter, symbolCounter, contCounter,
                 loadFile, eqv)
   where
@@ -47,9 +49,14 @@
 import Environment
 import WriteNumber
 
-errNumArgs name want got = throwError (NumArgs name want got)
-errTypeMismatch name want got = throwError (TypeMismatch name want got)
+errNumArgs :: MonadError LispError m =>
+  String -> Integer -> [LispVal] -> m a
+errNumArgs name want = throwError . NumArgs name want
 
+errTypeMismatch :: MonadError LispError m =>
+  String -> String -> LispVal -> m a
+errTypeMismatch name want = throwError . TypeMismatch name want
+
 genericBadArg :: [LispVal] -> String -> String -> Int
                  -> ThrowsError LispVal
 genericBadArg badArgList func want num =
@@ -61,7 +68,7 @@
                    -> IOThrowsError LispVal
 genericIOBadArg badArgList func want num =
   if length badArgList == num
-     then errTypeMismatch func want (badArgList !! 0)
+     then errTypeMismatch func want (head badArgList)
      else errNumArgs func (toInteger num) badArgList
 
 -- A bunch of library functions that don't do IO:
@@ -83,7 +90,7 @@
 
 isInteger :: [LispVal] -> ThrowsError LispVal
 isInteger [IntNumber _] = return lispTrue
-isInteger [RatNumber n] = return (Boolean ((denominator n) == 1))
+isInteger [RatNumber n] = return (Boolean (denominator n == 1))
 isInteger _ = return lispFalse
 
 isRational :: [LispVal] -> ThrowsError LispVal
@@ -123,7 +130,7 @@
 isProcedure :: [LispVal] -> ThrowsError LispVal
 isProcedure [Prim _] = return lispTrue
 isProcedure [IOPrim _] = return lispTrue
-isProcedure [Func _ _ _ _ _ _] = return lispTrue
+isProcedure [Func _ _ _ _ _ _ _] = return lispTrue
 isProcedure _ = return lispFalse
 
 isVector :: [LispVal] -> ThrowsError LispVal
@@ -138,7 +145,7 @@
 isZero [IntNumber n] =
   if n == 0 then return lispTrue else return lispFalse
 isZero [RatNumber n] =
-  if (n == 0) then return lispTrue else return lispFalse
+  if n == 0 then return lispTrue else return lispFalse
 isZero [FltNumber n] =
   if n == 0 then return lispTrue else return lispFalse
 isZero _ = return lispFalse
@@ -174,21 +181,21 @@
 
 lispIsNaN :: [LispVal] -> ThrowsError LispVal
 lispIsNaN [RatNumber n] =
-  return (Boolean (((numerator n) == 0) && ((denominator n) == 0)))
+  return (Boolean (numerator n == 0 && denominator n == 0))
 lispIsNaN [FltNumber n] = return (Boolean (isNaN n))
 lispIsNaN _ = return lispFalse
 
 lispIsInf :: [LispVal] -> ThrowsError LispVal
 lispIsInf [RatNumber n] = 
-  return (Boolean (((numerator n) /= 0) && ((denominator n) == 0)))
+  return (Boolean (numerator n /= 0 && denominator n == 0))
 lispIsInf [FltNumber n] = return (Boolean (isInfinite n))
 lispIsInf _ = return lispFalse
 
 lispIsFinite :: [LispVal] -> ThrowsError LispVal
 lispIsFinite [IntNumber _] = return lispTrue
-lispIsFinite [RatNumber n] = return (Boolean ((denominator n) /= 0))
+lispIsFinite [RatNumber n] = return (Boolean (denominator n /= 0))
 lispIsFinite [FltNumber n] =
-  return (Boolean (not ((isInfinite n) && (isNaN n))))
+  return (Boolean (not (isInfinite n && isNaN n)))
 lispIsFinite _ = return lispFalse
 
 lispIsEven :: [LispVal] -> ThrowsError LispVal
@@ -203,6 +210,7 @@
 
 lispId :: [LispVal] -> ThrowsError LispVal
 lispId [val@(_)] = return val
+lispId _ = progError "library/Id"
 
 lispNot :: [LispVal] -> ThrowsError LispVal
 lispNot [Boolean False] = return lispTrue
@@ -215,7 +223,7 @@
 unpackIntNum :: LispVal -> ThrowsError Integer
 unpackIntNum (IntNumber n) = return n
 unpackIntNum (RatNumber n) =
-  if (denominator n) /= 0
+  if denominator n /= 0
      then return (truncate n)
      else errTypeMismatch "<unpackIntNum>" "number" (RatNumber n)
 unpackIntNum (FltNumber n) = return (truncate n)
@@ -263,27 +271,29 @@
 scanRatNaN :: [LispVal] -> Bool
 scanRatNaN [] = False
 scanRatNaN (IntNumber _:vs) = scanRatNaN vs
-scanRatNaN (RatNumber v:vs) = if v == myRatNaN then True else scanRatNaN vs
+scanRatNaN (RatNumber v:vs) = (v == myRatNaN) || scanRatNaN vs
+scanRatNaN _ = progError "library/scanRatNaN"
 
 scanFltNaN :: [LispVal] -> Bool
 scanFltNaN [] = False
 scanFltNaN (IntNumber _:vs) = scanFltNaN vs
-scanFltNaN (RatNumber v:vs) = if v == myRatNaN then True else scanFltNaN vs
-scanFltNaN (FltNumber v:vs) = if isNaN v then True else scanFltNaN vs
+scanFltNaN (RatNumber v:vs) = (v == myRatNaN) || scanFltNaN vs
+scanFltNaN (FltNumber v:vs) = isNaN v || scanFltNaN vs
+scanFltNaN _ = progError "library/scanFltNaN"
 
 getType :: [LispVal] -> Int
 getType p = foldl1 max (map g p)
-            where g (IntNumber _) = isIntType
-                  g (RatNumber _) = isRatType
-                  g (FltNumber _) = isFltType
-                  g _ = isOther
+  where g (IntNumber _) = isIntType
+        g (RatNumber _) = isRatType
+        g (FltNumber _) = isFltType
+        g _ = isOther
 
 isNumType :: Int -> Bool
-isNumType n = (n == isIntType || n == isRatType || n == isFltType)
+isNumType n = n == isIntType || n == isRatType || n == isFltType
 
 intOrRat :: Rational -> LispVal
-intOrRat n | (denominator n) == 1  = (IntNumber (numerator n))
-           | otherwise             = (RatNumber n)
+intOrRat n | denominator n == 1  = IntNumber (numerator n)
+           | otherwise           = RatNumber n
 
 numericBinop :: String -> (Integer -> Integer -> Integer) ->
                 (Rational -> Rational -> Rational) ->
@@ -292,7 +302,7 @@
 numericBinop name intOp ratOp dblOp av =
   do let mytype = getType av
      if length av < 2
-        then errNumArgs name 2 ((String (show (length av))) : av)
+        then errNumArgs name 2 (String (show (length av)) : av)
         else if mytype == isIntType
                 then mapM unpackIntNum av >>=
                      return . IntNumber . foldl1 intOp
@@ -322,6 +332,8 @@
 -- wrappers around rational comparison operators so that
 -- we can deal properly with infinities and NaNs
 
+myRatEQ, myRatNE, myRatLT, myRatLE, myRatGT, myRatGE ::
+  Rational -> Rational -> Bool
 myRatEQ n1 n2 | n1 == myRatNaN || n2 == myRatNaN    = False
               | otherwise                           = n1 == n2
 
@@ -357,19 +369,19 @@
      if length av < 2
         then errNumArgs name 2 av
         else if mytype == isIntType
-                then do ll <- unpackIntNum (av !! 0)
+                then do ll <- unpackIntNum (head av)
                         rr <- unpackIntNum (av !! 1)
                         return (Boolean (intOp ll rr))
                 else if mytype == isRatType
                         then if scanRatNaN av
                                 then return (Boolean nanval)
-                                else do ll <- unpackRatNum (av !! 0)
+                                else do ll <- unpackRatNum (head av)
                                         rr <- unpackRatNum (av !! 1)
                                         return (Boolean (ratOp ll rr))
                         else if mytype == isFltType
                                 then if scanFltNaN av
                                         then return (Boolean nanval)
-                                        else do ll <- unpackFltNum (av !! 0)
+                                        else do ll <- unpackFltNum (head av)
                                                 rr <- unpackFltNum (av !! 1)
                                                 return (Boolean (dblOp ll rr))
                                 else errTypeMismatch name "number" (List av)
@@ -382,7 +394,7 @@
         else if isNumType mytype
                 then if scanFltNaN av
                         then return libFltNaN
-                        else unpackFltNum (av !! 0) >>=
+                        else unpackFltNum (head av) >>=
                              return . FltNumber . fun
                 else errTypeMismatch name "number" (List av)
 
@@ -419,30 +431,30 @@
 -- infinities were necessarily inexact.
 
 myrecip :: Rational -> Rational
-myrecip n | n == myRatNaN                      = myRatNaN
-          | (n == myRatPInf || n == myRatNInf) = 0
-          | n == 0                             = myRatPInf
-          | otherwise                          = (recip n)
+myrecip n | n == myRatNaN                    = myRatNaN
+          | n == myRatPInf || n == myRatNInf = 0
+          | n == 0                           = myRatPInf
+          | otherwise                        = recip n
 
 mymul :: Rational -> Rational -> Rational
-mymul n1 n2 | ((denominator n1 /= 0) &&
-              (denominator n2 /= 0))            = n1 * n2
+mymul n1 n2 | denominator n1 /= 0 &&
+              denominator n2 /= 0               = n1 * n2
             | (n1 == myRatNaN || n2 == myRatNaN) ||
               (n1 == 0 && (n2 == myRatPInf ||
                            n2 == myRatNInf)) ||
               (n2 == 0 && (n1 == myRatPInf ||
                            n1 == myRatNInf))    = myRatNaN
-            | (sg n1) == (sg n2)                = myRatPInf
+            | sg n1 == sg n2                    = myRatPInf
             | otherwise                         = myRatNInf
-              where sg n = if n > 0 then 1 else -1
+              where sg n = if n > 0 then 1::Int else -1::Int
 
 myadd :: Rational -> Rational -> Rational
-myadd n1 n2 | ((denominator n1 /= 0) &&
-              (denominator n2 /= 0))                 = n1 + n2
+myadd n1 n2 | denominator n1 /= 0 &&
+              denominator n2 /= 0                    = n1 + n2
             | (n1 == myRatNaN || n2 == myRatNaN) ||
               (n1 == myRatPInf && n2 == myRatNInf) ||
               (n1 == myRatNInf && n2 == myRatPInf)   = myRatNaN
-            | (denominator n1 /= 0)                  = n2
+            | denominator n1 /= 0                    = n2
             | otherwise                              = n1
 
 mymin :: Rational -> Rational -> Rational
@@ -458,18 +470,19 @@
      else max n1 n2
 
 mypow :: Rational -> Integer -> Rational
-mypow b e | (b == myRatNaN)                     = myRatNaN
-          | (b == myRatPInf && e > 0)           = myRatPInf
-          | (b == myRatPInf && e == 0)          = myRatNaN
-          | (b == myRatNInf && e > 0 && even e) = myRatPInf
-          | (b == myRatNInf && e > 0 && odd e)  = myRatNInf
-          | (b == myRatNInf && e == 0)          = myRatNaN
-          | (b == 0 && e > 0)                   = 0
-          | (e == 0)                            = 1 -- including 0**0,
-                                                    -- mandated by R6RS
-          | (e < 0)                             = mypow (myrecip b) (negate e)
-          | otherwise                           = b ^ e
+mypow b e | b == myRatNaN                     = myRatNaN
+          | b == myRatPInf && e > 0           = myRatPInf
+          | b == myRatPInf && e == 0          = myRatNaN
+          | b == myRatNInf && e > 0 && even e = myRatPInf
+          | b == myRatNInf && e > 0 && odd e  = myRatNInf
+          | b == myRatNInf && e == 0          = myRatNaN
+          | b == 0 && e > 0                   = 0
+          | e == 0                            = 1 -- including 0**0,
+                                                  -- mandated by R6RS
+          | e < 0                             = mypow (myrecip b) (negate e)
+          | otherwise                         = b ^ e
 
+addOp, mulOp :: [LispVal] -> ThrowsError LispVal
 addOp = numericBinop "+" (+) myadd (+)
 mulOp = numericBinop "*" (*) mymul (*)
 
@@ -482,15 +495,15 @@
 lispPlus (v:vs) = addOp (v:vs)
 
 lispMinus :: [LispVal] -> ThrowsError LispVal
+lispMinus [] = return (IntNumber 0)
 lispMinus [IntNumber n] = return (IntNumber (negate n))
 lispMinus [RatNumber n] = return (RatNumber (negate n))
 lispMinus [FltNumber n] = return (FltNumber (negate n))
 lispMinus (val:[]) = errTypeMismatch "-" "number" (String (show val))
 lispMinus (a:as) =
-  do aux <- addOp ((IntNumber 0):as)
+  do aux <- addOp (IntNumber 0 : as)
      rec <- lispMinus [aux]
-     res <- addOp (a:[rec])
-     return res
+     addOp (a:[rec])
 
 lispMul :: [LispVal] -> ThrowsError LispVal
 lispMul [] = return (IntNumber 1)
@@ -501,19 +514,19 @@
 lispMul (v:vs) = mulOp (v:vs)
 
 lispDiv :: [LispVal] -> ThrowsError LispVal
+lispDiv [] = return (IntNumber 1)
 lispDiv [IntNumber n] = return (RatNumber (myrecip (fromInteger n)))
 lispDiv [RatNumber n] =
   let nr = myrecip n
-  in if (denominator nr) == 1
+  in if denominator nr == 1
         then return (IntNumber (numerator nr))
         else return (RatNumber nr)
 lispDiv [FltNumber n] = return (FltNumber (1.0 / n))
 lispDiv (val:[]) = errTypeMismatch "/" "number" (String (show val))
 lispDiv (a:as) =
-  do aux <- mulOp ((IntNumber 1):as)
+  do aux <- mulOp (IntNumber 1 : as)
      rec <- lispDiv [aux]
-     res <- mulOp (a:[rec])
-     return res
+     mulOp (a:[rec])
 
 lispMin :: [LispVal] -> ThrowsError LispVal
 lispMin [] = errNumArgs "min" 1 []
@@ -541,8 +554,8 @@
            | x == 0                                   = if y > 0
                                                            then IntNumber 0
                                                            else libRatPInf
-           | (abs x) < 1 && y > 0 && isInfinite y     = IntNumber 0
-           | (abs x) > 1 && y < 0 && isInfinite y     = IntNumber 0
+           | abs x < 1 && y > 0 && isInfinite y       = IntNumber 0
+           | abs x > 1 && y < 0 && isInfinite y       = IntNumber 0
            | x == -1 && isInfinite y                  = libFltNaN
            | x < -1 && y > 0 && isInfinite y          = libFltNaN
            | x > -1 && x < 0 && y < 0 && isInfinite y = libFltNaN
@@ -551,40 +564,40 @@
 spow :: Rational -> Rational -> LispVal
 spow x y | x < -1 && y == myRatPInf                       = libRatNaN
          | x < 0 && x > -1 && y == myRatNInf              = libRatNaN
-         | x == -1 && (abs y) == myRatPInf                = libRatNaN
-         | x == myRatNInf && y > 0 && (denominator y) > 1 = libRatNaN
+         | x == -1 && abs y == myRatPInf                  = libRatNaN
+         | x == myRatNInf && y > 0 && denominator y > 1   = libRatNaN
          | x == myRatPInf && y == 0                       = libRatNaN
-         | (abs x) == myRatPInf && y > 0                  = libRatPInf
+         | abs x == myRatPInf && y > 0                    = libRatPInf
          | x > 1 && y == myRatPInf                        = libRatPInf
          | x > 0 && x < 1 && y == myRatNInf               = libRatPInf
-         | (abs x) == myRatPInf && y < 0                  = IntNumber 0
+         | abs x == myRatPInf && y < 0                    = IntNumber 0
          | x == 1                                         = IntNumber 1
          | otherwise          = fltpow (fromRational x) (fromRational y)
 
 ratpow :: Rational -> Rational -> LispVal
 ratpow x y =
-  if (denominator y) == 1
+  if denominator y == 1
      then let pow = mypow x (numerator y)
-          in if (denominator pow) == 1
-                then (IntNumber (numerator pow))
-                else (RatNumber pow)
-     else (spow x y)
+          in if denominator pow == 1
+                then IntNumber (numerator pow)
+                else RatNumber pow
+     else spow x y
 
 lispPow :: [LispVal] -> ThrowsError LispVal
 lispPow av =
   if length av /= 2
-     then do errNumArgs "**" 2 av
+     then errNumArgs "**" 2 av
      else do let mytype = getType av
              if isNumType mytype
-                then if (mytype == isIntType || mytype == isRatType)
+                then if mytype == isIntType || mytype == isRatType
                      then if scanRatNaN av
                              then return libRatNaN
-                             else do b <- unpackRatNum (av !! 0)
+                             else do b <- unpackRatNum (head av)
                                      e <- unpackRatNum (av !! 1)
                                      return (ratpow b e)
                      else if scanFltNaN av
                              then return libFltNaN
-                             else do b <- unpackFltNum (av !! 0)
+                             else do b <- unpackFltNum (head av)
                                      e <- unpackFltNum (av !! 1)
                                      return (fltpow b e)
                 else errTypeMismatch "expt" "number" (List av)
@@ -594,11 +607,16 @@
 boolBinop unpacker name op args =
   if length args /= 2
   then errNumArgs name 2 args
-  else do ll <- unpacker (args !! 0)
+  else do ll <- unpacker (head args)
           rr <- unpacker (args !! 1)
           return (Boolean (ll `op` rr))
 
+strBoolBinop :: String -> (String -> String -> Bool) -> [LispVal] ->
+                ThrowsError LispVal
 strBoolBinop = boolBinop unpackStr
+
+charBoolBinop :: String -> (Char -> Char -> Bool) -> [LispVal] ->
+                 ThrowsError LispVal
 charBoolBinop = boolBinop unpackChar
 
 car :: [LispVal] -> ThrowsError LispVal
@@ -614,30 +632,30 @@
 
 cons :: [LispVal] -> ThrowsError LispVal
 cons [xl, List []] = return (List [xl])
-cons [x, List xs] = return (List ([x] ++ xs))
-cons [x, DottedList xs xl] = return (DottedList ([x] ++ xs) xl)
+cons [x, List xs] = return (List (x : xs))
+cons [x, DottedList xs xl] = return (DottedList (x : xs) xl)
 cons [x1, x2] = return (DottedList [x1] x2)
 cons badArgList = errNumArgs "cons" 2 badArgList
 
 eqv :: [LispVal] -> Bool
-eqv [(Boolean v1), (Boolean v2)] = (v1 == v2)
-eqv [(Char c1), (Char c2)] = (c1 == c2)
-eqv [(IntNumber v1), (IntNumber v2)] = (v1 == v2)
-eqv [(RatNumber v1), (RatNumber v2)] = (v1 == v2)
-eqv [(FltNumber v1), (FltNumber v2)] = (v1 == v2) || ((isNaN v1) && (isNaN v2))
-eqv [(String v1), (String v2)] = (v1 == v2)
-eqv [(Symbol v1), (Symbol v2)] = (v1 == v2)
+eqv [(Boolean v1), (Boolean v2)] = v1 == v2
+eqv [(Char c1), (Char c2)] = c1 == c2
+eqv [(IntNumber v1), (IntNumber v2)] = v1 == v2
+eqv [(RatNumber v1), (RatNumber v2)] = v1 == v2
+eqv [(FltNumber v1), (FltNumber v2)] = v1 == v2 || (isNaN v1 && isNaN v2)
+eqv [(String v1), (String v2)] = v1 == v2
+eqv [(Symbol v1), (Symbol v2)] = v1 == v2
 eqv [(DottedList l1 t1), (DottedList l2 t2)] =
-    eqv [(List (l1 ++ [t1])), (List (l2 ++ [t2]))]
+    eqv [List (l1 ++ [t1]), List (l2 ++ [t2])]
 eqv [(List l1), (List l2)] =
-    ((length l1 == length l2) && (and (map eqvPair (zip l1 l2))))
+    length l1 == length l2 && all eqvPair (zip l1 l2)
     where eqvPair (x1,x2) = eqv [x1,x2]
 eqv [(Vector l1 v1), (Vector l2 v2)] =
-    ((l1 == l2) && (and (map eqvPair (zip (getval (DIM.toAscList v1))
-                                          (getval (DIM.toAscList v2))))))
+    l1 == l2 && all eqvPair (zip (getval (DIM.toAscList v1))
+                                 (getval (DIM.toAscList v2)))
     where eqvPair (x1,x2) = eqv [x1,x2]
           getval [] = []
-          getval ((_,v):vs) = v:(getval vs)
+          getval ((_,v):vs) = v : getval vs
 eqv _ = False
 
 eqvFunc :: [LispVal] -> ThrowsError LispVal
@@ -655,7 +673,7 @@
 char2str :: [LispVal] -> ThrowsError LispVal
 char2str [] = return (String "")
 char2str [List chars] = char2str chars
-char2str chars = mapM unpackChar chars >>= return . String . (foldr (:) [])
+char2str chars = mapM unpackChar chars >>= return . String . foldr (:) []
 
 str2char :: [LispVal] -> ThrowsError LispVal
 str2char [] = return (List [])
@@ -671,8 +689,9 @@
 str2symb [String []] = genericBadArg [String ""] "string->symbol" "string" 1
 str2symb [String s] = return (Symbol (sanitize s))
   where sanitize (c:cs) = schar isAlpha c : map (schar isAlphaNum) cs
-        schar pred c =
-          if (pred c) || (c `elem` specialSymbolChars) then c else '_'
+        sanitize [] = "_"
+        schar pr c =
+          if pr c || elem c specialSymbolChars then c else '_'
 str2symb badArgList = genericBadArg badArgList "string->symbol" "string" 1
 
 readNum :: [LispVal] -> ThrowsError LispVal
@@ -695,7 +714,7 @@
 lispFloor :: [LispVal] -> ThrowsError LispVal
 lispFloor [IntNumber c] = return (IntNumber c)
 lispFloor [RatNumber c] =
-  if (denominator c) /= 0
+  if denominator c /= 0
      then return (IntNumber (floor c))
      else return (RatNumber c)
 lispFloor [FltNumber c] = return (IntNumber (floor c))
@@ -704,7 +723,7 @@
 lispTruncate :: [LispVal] -> ThrowsError LispVal
 lispTruncate [IntNumber c] = return (IntNumber c)
 lispTruncate [RatNumber c] =
-  if (denominator c) /= 0
+  if denominator c /= 0
      then return (IntNumber (truncate c))
      else return (RatNumber c)
 lispTruncate [FltNumber c] = return (IntNumber (truncate c))
@@ -719,8 +738,8 @@
 
 roundToAP :: RealFrac a => a -> Integer -> Integer -> a
 roundToAP n b d =
-  let bd = (fromInteger (b^d))
-  in (fromInteger (round (n * bd)))/bd
+  let bd = fromInteger (b^d)
+  in fromInteger (round (n * bd)) / bd
 
 -- equivalent of the above, except with the truncation point to the left
 -- of the decimal point; that means the result is always an integer
@@ -728,12 +747,12 @@
 roundToAN :: RealFrac a => a -> Integer -> Integer -> Integer
 roundToAN n b d =
   let bd = b^d
-  in bd*(round (n/(fromInteger bd)))
+  in bd * round (n / fromInteger bd)
 
 lispRound :: [LispVal] -> ThrowsError LispVal
 lispRound [IntNumber c] = return (IntNumber c)
 lispRound [RatNumber c] =
-  if (denominator c) /= 0
+  if denominator c /= 0
      then return (IntNumber (round c))
      else return (RatNumber c)
 lispRound [FltNumber c] = return (IntNumber (round c))
@@ -742,27 +761,27 @@
      then if d >= 0
              then return (IntNumber c)
              else return (IntNumber (roundToAN (toRational c) b (- d)))
-     else throwError (Default ("bad base arg to round: " ++ (show b)))
+     else throwError (Default ("bad base arg to round: " ++ show b))
 lispRound [RatNumber c, IntNumber b, IntNumber d] =
-  if (denominator c) /= 0
+  if denominator c /= 0
      then if b > 1
              then if d > 0
                      then return (RatNumber (roundToAP c b d))
                      else return (IntNumber (roundToAN c b (- d)))
-             else throwError (Default ("bad base arg to round: " ++ (show b)))
+             else throwError (Default ("bad base arg to round: " ++ show b))
      else return (RatNumber c)
 lispRound [FltNumber c, IntNumber b, IntNumber d] =
   if b > 1
      then if d > 0
              then return (FltNumber (roundToAP c b d))
              else return (IntNumber (roundToAN c b (- d)))
-     else throwError (Default ("bad base arg to round: " ++ (show b)))
+     else throwError (Default ("bad base arg to round: " ++ show b))
 lispRound badArgList = genericBadArg badArgList "round" "number" 1
 
 lispCeiling :: [LispVal] -> ThrowsError LispVal
 lispCeiling [IntNumber c] = return (IntNumber c)
 lispCeiling [RatNumber c] =
-  if (denominator c) /= 0
+  if denominator c /= 0
      then return (IntNumber (ceiling c))
      else return (RatNumber c)
 lispCeiling [FltNumber c] = return (IntNumber (ceiling c))
@@ -788,9 +807,10 @@
                           _ -> errNumArgs "atan" 2 av
         else errTypeMismatch "atan" "number" (List av)
   where at2 (y:x:[]) = atan2 y x
+        at2 _ = progError "library/ATan2"
 
 lispListFromArgs :: [LispVal] -> ThrowsError LispVal
-lispListFromArgs vals = return (List vals)
+lispListFromArgs = return . List
 
 lispReverse :: [LispVal] -> ThrowsError LispVal
 lispReverse [List lst] = return (List (reverse lst))
@@ -831,13 +851,11 @@
 lispILog badArgList = genericBadArg badArgList "ilog" "integer" 1
 
 lispFactorial :: [LispVal] -> ThrowsError LispVal
-lispFactorial [IntNumber n] =
-  if n > 0
-     then return (IntNumber (product [1 .. n]))
-     else if n == 0
-             then return (IntNumber 1)
-             else genericBadArg [IntNumber n] "factorial"
-                                "non-negative integer" 1
+lispFactorial [IntNumber n]
+  | n == 0    = return (IntNumber 1)
+  | n > 0     = return (IntNumber (product [1 .. n]))
+  | otherwise = genericBadArg [IntNumber n] "factorial"
+                              "non-negative integer" 1
 lispFactorial badArgList = genericBadArg badArgList "factorial" "integer" 1
 
 -- Vector primitives
@@ -849,20 +867,20 @@
      then return (Vector n (DIM.fromAscList (addkey val (fromInteger n))))
      else errTypeMismatch "make-vector" "n > 0" (IntNumber n)
   where addkey _ 0 = []
-        addkey v k = ((k-1), v):(addkey v (k-1))
+        addkey v k = ((k-1), v) : addkey v (k-1)
 lispMakeVector badArgList = genericBadArg badArgList "make-vector" "integer" 1
 
 lispVecFromArgs :: [LispVal] -> ThrowsError LispVal
 lispVecFromArgs vals =
   return (Vector (toInteger (length vals)) (DIM.fromAscList (addkey 0 vals)))
   where addkey _ [] = []
-        addkey n (v:vs) = (n, v):(addkey (n+1) vs)
+        addkey n (v:vs) = (n, v) : addkey (n+1) vs
 
 lispListToVec :: [LispVal] -> ThrowsError LispVal
 lispListToVec [List vals] =
   return (Vector (toInteger (length vals)) (DIM.fromAscList (addkey 0 vals)))
   where addkey _ [] = []
-        addkey n (v:vs) = (n, v):(addkey (n+1) vs)
+        addkey n (v:vs) = (n, v) : addkey (n+1) vs
 lispListToVec badArgList =
   genericBadArg badArgList "list->vector" "list" 1
 
@@ -870,7 +888,7 @@
 lispVecToList [Vector _ vec] =
   return (List (getval (DIM.toAscList vec)))
   where getval [] = []
-        getval ((_,v):vs) = v:(getval vs)
+        getval ((_,v):vs) = v : getval vs
 lispVecToList badArgList =
   genericBadArg badArgList "vector->list" "vector" 1
 
@@ -880,7 +898,7 @@
 
 lispVecRef :: [LispVal] -> ThrowsError LispVal
 lispVecRef [Vector len vec, IntNumber n] =
-  if (n >= 0 && n < len)
+  if n >= 0 && n < len
      then return (DIM.findWithDefault lispFalse (fromInteger n) vec)
      else throwError (VectorBounds len (IntNumber n))
 lispVecRef badArgList =
@@ -895,7 +913,7 @@
 getfn ps (Just v) body = getfn1 (DottedList (map Symbol ps) (Symbol v)) body
 
 proc2data :: [LispVal] -> ThrowsError LispVal
-proc2data [Func pars var body _ _ _] = return (getfn pars var body)
+proc2data [Func pars var body _ _ _ _] = return (getfn pars var body)
 proc2data [Delay obj _ _] = return obj
 proc2data [Prim _] =
   throwError (Default "procedure->data can't handle builtin functions")
@@ -950,7 +968,7 @@
 
 bitsGet :: [LispVal] -> ThrowsError LispVal
 bitsGet [IntNumber n1, IntNumber n2] =
-  return (IntNumber (n1 .&. (bit (fromInteger n2))))
+  return (IntNumber (n1 .&. bit (fromInteger n2)))
 bitsGet badArgList = genericBadArg badArgList "bits-get" "integer" 2
 
 bitsIsSet :: [LispVal] -> ThrowsError LispVal
@@ -1094,6 +1112,8 @@
 -- This converts a system-level error into a lisp-level error by the
 -- kinda-funky (Default (show err)), assuming we don't swallow the error
 
+doIOAction :: (MonadIO m, MonadError LispError m) =>
+  IO a -> (a -> LispVal) -> (IOError -> Bool) -> m LispVal
 doIOAction action ctor epred =
   do ret <- liftIO (try action)
      case ret of
@@ -1108,10 +1128,15 @@
 -- generally we want to hear about errors, but EOF when reading a line or
 -- character isn't really an error, so we silence that one.
 
+dropToBool :: t -> LispVal
 dropToBool _ = lispTrue
+
+allErrs :: t -> Bool
 allErrs _ = True
-noEOF err = not (isEOFError err)
 
+noEOF :: IOError -> Bool
+noEOF = not . isEOFError
+
 makePort :: IOMode -> [LispVal] -> IOThrowsError LispVal
 makePort mode [String filename] =
   doIOAction (openFile filename mode) Port allErrs
@@ -1150,6 +1175,7 @@
     case str of
          Boolean False -> throwError (Default "operation failed")
          String val -> liftThrows (readExprList val)
+         _ -> progError "library/loadFile"
 
 readAll :: [LispVal] -> IOThrowsError LispVal
 readAll [String filename] = liftM List (loadFile filename)
@@ -1162,7 +1188,7 @@
   where outStr (String s) = doIOAction (hPutStr port s) dropToBool allErrs
         outStr (Char c) = doIOAction (hPutChar port c) dropToBool allErrs
         outStr notS = genericIOBadArg [notS] "write-string" "string" 1
-lispPutStr (s:ss) = lispPutStr ((Port stdout):s:ss)
+lispPutStr (s:ss) = lispPutStr (Port stdout : s : ss)
 
 flushPort :: [LispVal] -> IOThrowsError LispVal
 flushPort [] = flushPort [Port stdout]
@@ -1242,27 +1268,23 @@
 
 lispGetCurrentDir :: [LispVal] -> IOThrowsError LispVal
 lispGetCurrentDir [] =
-  doIOAction (getCurrentDirectory) String allErrs
+  doIOAction getCurrentDirectory String allErrs
 lispGetCurrentDir badArgList =
   genericIOBadArg badArgList "get-current-directory" "nothing" 0
 
 lispGetDirContents :: [LispVal] -> IOThrowsError LispVal
 lispGetDirContents [String dirname] =
-  doIOAction (getDirectoryContents dirname) loS allErrs
-  where loS arr = List (toS arr)
-        toS [] = []
-        toS (str:strs) = (String str):(toS strs)
+  doIOAction (getDirectoryContents dirname) (List . map String) allErrs
 
 lispGetDirContents badArgList =
   genericIOBadArg badArgList "read-directory" "string" 1
 
 lispGetEnv :: [LispVal] -> IOThrowsError LispVal
 lispGetEnv [] =
-  doIOAction (getEnvironment) loSS allErrs
-  where loSS arr = List (toSS arr)
-        toSS [] = []
+  doIOAction getEnvironment (List . toSS) allErrs
+  where toSS [] = []
         toSS ((key,val):strs) =
-             (DottedList [String key] (String val)):(toSS strs)
+             DottedList [String key] (String val) : toSS strs
 lispGetEnv [String key] =
   doIOAction (getEnvDefault key "") String allErrs
 lispGetEnv badArgList =
@@ -1281,28 +1303,28 @@
 
 
 lispEpochTime :: [LispVal] -> IOThrowsError LispVal
-lispEpochTime [] = doIOAction (getClockTime) getET allErrs
+lispEpochTime [] = doIOAction getClockTime getET allErrs
   where getET (TOD sec psec) =
-              FltNumber ((fromInteger sec) + 1.0e-12*(fromInteger psec))
+              FltNumber (fromInteger sec + 1.0e-12 * fromInteger psec)
 lispEpochTime badArgList = genericIOBadArg badArgList "epochtime" "nothing" 0
 
 lispLocalTime :: [LispVal] -> IOThrowsError LispVal
-lispLocalTime [] = doIOAction (getClockTime) toS allErrs
-  where toS val = String (show val)
+lispLocalTime [] = doIOAction getClockTime toS allErrs
+  where toS = String . show
 lispLocalTime [IntNumber n] =
   doIOAction (toCalendarTime (TOD n 0)) toS allErrs
-  where toS val = String (calendarTimeToString val)
+  where toS = String . calendarTimeToString
 lispLocalTime [RatNumber n] =
   doIOAction (toCalendarTime (TOD (round n) 0)) toS allErrs
-  where toS val = String (calendarTimeToString val)
+  where toS = String . calendarTimeToString
 lispLocalTime [FltNumber n] =
   doIOAction (toCalendarTime (TOD (round n) 0)) toS allErrs
-  where toS val = String (calendarTimeToString val)
+  where toS = String . calendarTimeToString
 lispLocalTime badArgList = genericIOBadArg badArgList "localtime" "nothing" 0
 
 lispUTCTime :: [LispVal] -> IOThrowsError LispVal
-lispUTCTime [] = doIOAction (getClockTime) toS allErrs
-  where toS val = String (calendarTimeToString (toUTCTime val))
+lispUTCTime [] = doIOAction getClockTime toS allErrs
+  where toS = String . calendarTimeToString . toUTCTime
 lispUTCTime [IntNumber n] =
   return (String (calendarTimeToString (toUTCTime (TOD n 0))))
 lispUTCTime [RatNumber n] =
@@ -1313,8 +1335,8 @@
 
 lispGetCPUTime :: [LispVal] -> IOThrowsError LispVal
 lispGetCPUTime [] =
-  doIOAction (getCPUTime) toS allErrs
-  where toS val = FltNumber ((fromInteger val)/1.0e12)
+  doIOAction getCPUTime toS allErrs
+  where toS val = FltNumber (1.0e-12 * fromInteger val)
 lispGetCPUTime badArgList =
   genericIOBadArg badArgList "cputime" "nothing" 0
 
@@ -1331,7 +1353,7 @@
         getET (accessTime stat),
         getET (modificationTime stat),
         getET (statusChangeTime stat)]
-  where getET t = FltNumber (realToFrac t)
+  where getET = FltNumber . realToFrac
 
 lispGetFileStatus :: [LispVal] -> IOThrowsError LispVal
 lispGetFileStatus [String filename] =
@@ -1404,7 +1426,7 @@
 lispRandExp :: [LispVal] -> IOThrowsError LispVal
 lispRandExp [FltNumber m] =
   if m > 0
-     then getrand >>= return . FltNumber . (sc m) . negate . log
+     then getrand >>= return . FltNumber . (/ m) . negate . log
      else genericIOBadArg [FltNumber m] "random-exponential" "positive rate" 1
   where getrand =
           do val <- lispRandUni []
@@ -1412,7 +1434,7 @@
                 then getrand
                 else return (getnum val)
         getnum (FltNumber n) = n
-        sc s v = v/s
+        getnum _ = progError "library/RandExp/getnum"
 lispRandExp [] = lispRandExp [FltNumber 1.0]
 lispRandExp [IntNumber m] = lispRandExp [FltNumber (fromInteger m)]
 lispRandExp [RatNumber m] = lispRandExp [FltNumber (fromRational m)]
@@ -1424,19 +1446,20 @@
   if s > 0
      then do x1 <- getrand
              x2 <- getrand
-             let a = s*sqrt (-2.0*(log x1))
+             let a = s*sqrt (-2.0 * log x1)
                  b = 2.0*pi*x2
-                 y1 = m + a*(cos b)
-                 y2 = m + a*(sin b)
+                 y1 = m + a * cos b
+                 y2 = m + a * sin b
              return (List [FltNumber y1, FltNumber y2])
      else throwError (Default ("random-normal-pair needs a positive stddev,"
-                     ++ " got " ++ (show s)))
+                     ++ " got " ++ show s))
   where getrand =
           do val <- lispRandUni []
              if getnum val == 0
                 then getrand
                 else return (getnum val)
         getnum (FltNumber n) = n
+        getnum _ = progError "library/RandNorm/getnum"
 lispRandNorm [] = lispRandNorm [FltNumber 0.0, FltNumber 1.0]
 lispRandNorm [IntNumber m, IntNumber s] =
   lispRandNorm [FltNumber (fromInteger m), FltNumber (fromInteger s)]
@@ -1465,17 +1488,19 @@
      then do val <- doit (exp (-lambda)) (-1) (1 :: Double)
              return (IntNumber val)
      else throwError (Default ("random-poisson needs a positive lambda,"
-                     ++ " got " ++ (show lambda)))
+                     ++ " got " ++ show lambda))
   where doit l k p =
           do r <- lispRandUni []
-             let pp = p*(getnum r)
+             let pp = p * getnum r
                  kp = k + 1
              if pp < l
                 then return kp
                 else doit l kp pp
         getnum (FltNumber n) = n
+        getnum _ = progError "library/RandPoisson/getnum"
 lispRandPoisson [IntNumber m] = lispRandPoisson [FltNumber (fromInteger m)]
 lispRandPoisson [RatNumber m] = lispRandPoisson [FltNumber (fromRational m)]
+lispRandPoisson _ = progError "library/RandPoisson"
 
 lispSeedRandom :: [LispVal] -> IOThrowsError LispVal
 lispSeedRandom [IntNumber n] =
@@ -1557,6 +1582,7 @@
           Left err -> throwError (Default (show err))
           Right val -> return (Port (val2 val))
   where val2 (_, Just hout, _, _) = hout
+        val2 _ = progError "library/ReadCmd"
 lispReadCmd badArgList =
   genericIOBadArg badArgList "run-read-command" "command+dir" 2
 
@@ -1570,6 +1596,7 @@
           Left err -> throwError (Default (show err))
           Right val -> return (Port (val1 val))
   where val1 (Just hin, _, _, _) = hin
+        val1 _ = progError "library/WriteCmd"
 lispWriteCmd badArgList =
   genericIOBadArg badArgList "run-write-command" "command+dir" 2
 
@@ -1632,10 +1659,10 @@
 -- A couple of predefined data values
 
 ioPorts :: [(String, LispVal)]
-ioPorts = [("stdin", (Port stdin)),
-           ("stdout", (Port stdout)),
-           ("stderr", (Port stderr)),
-           ("pi", (FltNumber pi))]
+ioPorts = [("stdin", Port stdin),
+           ("stdout", Port stdout),
+           ("stderr", Port stderr),
+           ("pi", FltNumber pi)]
 
 -- And finally some stuff for internal work
 
@@ -1662,6 +1689,6 @@
 
 primitiveBindings :: IO Env
 primitiveBindings = newIORef [] >>=
-  (flip bindVars (internals ++ map (mkf IOPrim) ioPrimitives ++
-                  map (mkf Prim) primitives ++ ioPorts))
+  flip bindVars (internals ++ map (mkf IOPrim) ioPrimitives ++
+                 map (mkf Prim) primitives ++ ioPorts)
   where mkf constructor (var, func) = (var, constructor func)
diff --git a/LispData.hs b/LispData.hs
--- a/LispData.hs
+++ b/LispData.hs
@@ -18,7 +18,7 @@
 along with haskeem; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
-$Id: lispdata.hs,v 1.17 2009-08-06 05:05:15 uwe Exp $ -}
+$Id: lispdata.hs,v 1.21 2010-01-05 05:23:34 uwe Exp $ -}
 
 module LispData
     (LispVal(Symbol, Boolean, Char, Delay, DottedList, IntNumber,
@@ -27,9 +27,11 @@
      LispError(NumArgs, TypeMismatch, Parser, BadSpecial, NotFunction,
                UnboundVar, Default, OutOfRange, VectorBounds, UserException,
                DelCont),
-     ThrowsError, Env, IOThrowsError, liftThrows,
+     ThrowsError, Env, PureEnv, IOThrowsError, liftThrows,
      myRatPInf, myRatNInf, myRatNaN, myFltPInf, myFltNInf, myFltNaN,
-     lispTrue, lispFalse) where
+     lispTrue, lispFalse,
+     EEnv(EEnv), eeE, eePE, eeDC, eeQL, eeNewE, eeNewPE, eeNewDC,
+     eeQLIncr, eeQLDecr, progError) where
 import Prelude
 import IO hiding (try)
 import Data.Char
@@ -54,14 +56,18 @@
 -- floating-point infinities and NaN
 
 myFltPInf, myFltNInf, myFltNaN :: Double
-myFltPInf = (1.0e99 ** 1.0e99)	-- probably big enough...
-myFltNInf = (-myFltPInf)
+myFltPInf = 1.0e99 ** 1.0e99	-- probably big enough...
+myFltNInf = -myFltPInf
 myFltNaN = sqrt (-1.0)
 
 -- An environment: a table connecting names of objects and values
 
 type Env = IORef [(String, IORef LispVal)]
 
+-- A pure env: just strings and LispVals
+
+type PureEnv = [(String, LispVal)]
+
 -- A lisp value: these are the stuff which normally gets processed
 
 data LispVal = Symbol String
@@ -79,7 +85,8 @@
                      body :: [LispVal],
                      closure :: Env,
                      name :: (Maybe String),
-                     macro :: Bool}
+                     macro :: Bool,
+                     cont :: Bool}
              | Delay {obj :: LispVal,
                       closure :: Env,
                       tag :: String}
@@ -96,33 +103,33 @@
 showVal (Boolean False) = "#f"
 showVal (IntNumber num) = show num
 showVal (RatNumber num) =
-  (show (numerator num)) ++ "/" ++ (show (denominator num))
+  show (numerator num) ++ "/" ++ show (denominator num)
 showVal (FltNumber num) = show num
 showVal (String str) = "\"" ++ str ++ "\""
-showVal (List lst) = "(" ++ (unwords (map showVal lst)) ++ ")"
-showVal (DottedList lst cab) = "(" ++ (unwords (map showVal lst))
-                               ++ " . " ++ (showVal cab) ++ ")"
+showVal (List lst) = "(" ++ unwords (map showVal lst) ++ ")"
+showVal (DottedList lst cab) = "(" ++ unwords (map showVal lst)
+                               ++ " . " ++ showVal cab ++ ")"
 -- the control-character printing and parsing assumes ASCII
-showVal (Char ch) | (ch == (chr 0))   = "#\\nul"
-                  | (ch == (chr 7))   = "#\\alarm"
-                  | (ch == (chr 8))   = "#\\backspace"
-                  | (ch == '\t')      = "#\\tab"
-                  | (ch == '\n')      = "#\\linefeed"
-                  | (ch == (chr 11))  = "#\\vtab"
-                  | (ch == (chr 12))  = "#\\page"
-                  | (ch == '\r')      = "#\\return"
-                  | (ch == (chr 27))  = "#\\esc"
-                  | (ch == ' ')       = "#\\space"
-                  | (ch == (chr 127)) = "#\\delete"
-                  | isControl ch      = "#\\^" ++ [chr (ord ch + ord 'A' - 1)]
-                  | isPrint ch        = "#\\" ++ [ch]
-                  | otherwise         = [ch]
+showVal (Char ch) | ch == chr 0   = "#\\nul"
+                  | ch == chr 7   = "#\\alarm"
+                  | ch == chr 8   = "#\\backspace"
+                  | ch == '\t'    = "#\\tab"
+                  | ch == '\n'    = "#\\linefeed"
+                  | ch == chr 11  = "#\\vtab"
+                  | ch == chr 12  = "#\\page"
+                  | ch == '\r'    = "#\\return"
+                  | ch == chr 27  = "#\\esc"
+                  | ch == ' '     = "#\\space"
+                  | ch == chr 127 = "#\\delete"
+                  | isControl ch  = "#\\^" ++ [chr (ord ch + ord 'A' - 1)]
+                  | isPrint ch    = "#\\" ++ [ch]
+                  | otherwise     = [ch]
 showVal (Prim _) = "<primitive>"
-showVal (Func {params = args, vararg = varargs, body = bd,
-               closure = _, name = nm, macro = ismac}) =
+showVal (Func {params = args, vararg = varargs, body = _,
+               closure = _, name = nm, macro = ismac, cont = _}) =
   let lopen = if ismac then "<macro" else "(lambda"
       lclose = if ismac then ">" else ")"
-      inner = lopen ++ " (" ++ (unwords args) ++
+      inner = lopen ++ " (" ++ unwords args ++
               (case varargs of
                     Nothing -> ""
                     Just arg -> " . " ++ arg) ++ ") " ++
@@ -133,10 +140,10 @@
 showVal (IOPrim _) = "<IO primitive>"
 showVal (Port _) = "<IO port>"
 showVal (Socket _) = "<IO socket>"
-showVal (Delay {obj = o, closure = _, tag = _}) = "<promise>" ++ (show o)
+showVal (Delay {obj = o, closure = _, tag = _}) = "<promise>" ++ show o
 
 showVal (Vector _ vals) =
-  "#(" ++ (unwords (map showVal (DIM.elems vals))) ++ ")"
+  "#(" ++ unwords (map showVal (DIM.elems vals)) ++ ")"
 
 -- True and False at the scheme level
 
@@ -168,20 +175,20 @@
 showError :: LispError -> String
 showError (NumArgs func expected found) =
   func ++ " expected " ++ show expected ++ " args; got values \"" ++
-  (unwords (map showVal found)) ++ "\""
+  unwords (map showVal found) ++ "\""
 showError (TypeMismatch func expected found) =
-  func ++ " expected " ++ expected ++ " args; got " ++ (show found)
-showError (Parser parseErr) = "Parse error at " ++ (show parseErr)
-showError (BadSpecial msg form) = msg ++ ": \"" ++ (show form) ++ "\""
-showError (NotFunction msg func) = msg ++ ": " ++ (show func)
+  func ++ " expected " ++ expected ++ " args; got " ++ show found
+showError (Parser parseErr) = "Parse error at " ++ show parseErr
+showError (BadSpecial msg form) = msg ++ ": \"" ++ show form ++ "\""
+showError (NotFunction msg func) = msg ++ ": " ++ show func
 showError (UnboundVar msg var) = msg ++ ": " ++ var
 showError (Default msg) = msg
-showError (OutOfRange func val) = func ++ " arg out of range: " ++ (show val)
+showError (OutOfRange func val) = func ++ " arg out of range: " ++ show val
 showError (VectorBounds len n) =
-  "vector index out of bounds: " ++ (show n) ++
-  " not in [0.." ++ (show (len - 1)) ++ "]"
-showError (UserException val) = "user exception " ++ (show val)
-showError (DelCont val) = "delcont value " ++ (show val)
+  "vector index out of bounds: " ++ show n ++
+  " not in [0.." ++ show (len - 1) ++ "]"
+showError (UserException val) = "user exception " ++ show val
+showError (DelCont val) = "delcont value " ++ show val
 
 type ThrowsError = Either LispError
 
@@ -192,3 +199,36 @@
 liftThrows :: ThrowsError a -> IOThrowsError a
 liftThrows (Left err) = throwError err
 liftThrows (Right val) = return val
+
+-- An extended environment: environment plus delimited continuations stuff
+-- plus quote-level stuff plus whatever else we may need later
+
+data EEnv = EEnv Env PureEnv [[LispVal]] Integer
+
+eeE :: EEnv -> Env
+eeE  (EEnv e _ _ _) = e
+
+eePE :: EEnv -> PureEnv
+eePE (EEnv _ e _ _) = e
+
+eeDC :: EEnv -> [[LispVal]]
+eeDC (EEnv _ _ d _) = d
+
+eeQL :: EEnv -> Integer
+eeQL (EEnv _ _ _ q) = q
+
+eeNewE :: EEnv -> Env -> EEnv
+eeNewE  (EEnv _ pe d q) e = EEnv e pe d q
+
+eeNewPE :: EEnv -> PureEnv -> EEnv
+eeNewPE (EEnv e _ d q) pe = EEnv e pe d q
+
+eeNewDC :: EEnv -> [[LispVal]] -> EEnv
+eeNewDC (EEnv e pe _ q) d = EEnv e pe d q
+
+eeQLIncr, eeQLDecr :: EEnv -> EEnv
+eeQLIncr (EEnv e pe d q) = EEnv e pe d (q + 1)
+eeQLDecr (EEnv e pe d q) = EEnv e pe d (q - 1)
+
+progError :: String -> a
+progError = error . ("internal error at " ++)
diff --git a/Parser.hs b/Parser.hs
--- a/Parser.hs
+++ b/Parser.hs
@@ -18,7 +18,7 @@
 along with haskeem; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
-$Id: parser.hs,v 1.16 2009-08-06 05:05:15 uwe Exp $ -}
+$Id: parser.hs,v 1.17 2010-01-05 05:23:34 uwe Exp $ -}
 
 module Parser (readExpr, readExprList, readNumber, specialSymbolChars) where
 import Prelude
@@ -36,11 +36,7 @@
 -- scheme "shell" scripts: for the rest of the program, it's a comment
 
 hashbang :: Parser Char
-hashbang =
-  do char '#'
-     char '!'
-     many (noneOf "\r\n")
-     return ' '
+hashbang = char '#' >> char '!' >> many (noneOf "\r\n") >> return ' '
 
 -- semicolon to end-of-line, the oldest style of lisp comment
 
@@ -55,6 +51,7 @@
 
 -- This is not quite R6RS-compliant: R6RS allows '.'
 
+specialSymbolChars :: String
 specialSymbolChars = "!$%&*+-/:<=>?@^_~"
 
 symbol :: Parser Char
@@ -70,18 +67,18 @@
 
 namedChar :: Parser Char
 namedChar =
-  do name <- (string "alarm"
+  do name <- string "alarm"
           <|> string "backspace"
           <|> string "delete"
           <|> string "esc"
           <|> string "linefeed"
-          <|> (TPCP.try (string "newline"))
+          <|> TPCP.try (string "newline")
           <|> string "nul"
           <|> string "page"
           <|> string "return"
           <|> string "space"
           <|> string "tab"
-          <|> string "vtab")
+          <|> string "vtab"
      case name of
           "nul"       -> return (chr 0)
           "alarm"     -> return (chr 7)
@@ -95,12 +92,13 @@
           "esc"       -> return (chr 27)
           "space"     -> return ' '
           "delete"    -> return (chr 127)
+          _ -> progError "namedChar"
 
 parseChar :: Parser LispVal
 parseChar =
   do char '#'
      char '\\'
-     c <- (TPCP.try controlChar) <|> (TPCP.try namedChar) <|> anyChar
+     c <- TPCP.try controlChar <|> TPCP.try namedChar <|> anyChar
      return (Char c)
 
 -- This is not quite R6RS-compliant: R6RS requires a hex escape spec,
@@ -128,12 +126,13 @@
             't' -> lispTrue
             'T' -> lispTrue
             'f' -> lispFalse
-            'F' -> lispFalse)
+            'F' -> lispFalse
+            _ -> progError "parseBool")
 
 parseString :: Parser LispVal
 parseString =
   do char '"'
-     x <- many (escChar <|> (noneOf "\""))
+     x <- many (escChar <|> noneOf "\"")
      char '"'
      return (String x)
 
@@ -145,19 +144,19 @@
 
 readBaseInt :: Integer -> String -> Integer
 readBaseInt b s = foldl ma 0 s
-                  where ma v1 v2 = b*v1 + (toInteger (digitToInt v2))
+                  where ma v1 v2 = b*v1 + toInteger (digitToInt v2)
 
 readBaseFrac :: Integer -> String -> Double
 readBaseFrac _ [] = 0.0
 readBaseFrac b s = r * foldr ma 0 s where
-                   r = 1.0/(fromInteger b)
+                   r = 1.0 / fromInteger b
                    ma v1 v2 = fromIntegral (digitToInt v1) + r*v2
 
 parseHdr :: Parser (Char, Integer)
 parseHdr =
   do b <- option 'd' (char '#' >> oneOf "bodxBODX")
      s <- option '+' (oneOf "+-")
-     let base = (case b of
+     let base = case b of
                  'b' -> 2
                  'B' -> 2
                  'o' -> 8
@@ -165,7 +164,8 @@
                  'd' -> 10
                  'D' -> 10
                  'x' -> 16
-                 'X' -> 16)
+                 'X' -> 16
+                 _ -> progError "parseHdr"
      return (s, base)
 
 baseDigits :: Integer -> String
@@ -173,6 +173,7 @@
 baseDigits 8  = "01234567"
 baseDigits 10 = "0123456789"
 baseDigits 16 = "0123456789abcdefABCDEF"
+baseDigits _  = progError "baseDigits"
 
 int :: String
 int = "int"
@@ -200,7 +201,7 @@
 
 parseExp :: Integer -> Parser Integer
 parseExp b =
-  do if b == 16 then (oneOf "xX") else (oneOf "eExX")
+  do oneOf (if b == 16 then "xX" else "eExX")
      s <- option '+' (oneOf "+-")
      num <- many1 (oneOf (baseDigits b))
      let e = readBaseInt b num
@@ -210,7 +211,7 @@
 powi b e | e == 0    = 1
          | e < 0     = error "negative exponent in powi"
          | even e    = powi (b*b) (e `quot` 2)
-         | otherwise = b * (powi b (e - 1))
+         | otherwise = b * powi b (e - 1)
 
 pow :: Integer -> Integer -> Double
 pow b e =
@@ -223,12 +224,12 @@
 parseIntOrFlt :: Parser LispVal
 parseIntOrFlt =
   do (s, b) <- parseHdr
-     (ip, fp) <- (parseF1 b) <|> (parseF2 b)
+     (ip, fp) <- parseF1 b <|> parseF2 b
      e <- option 0 (parseExp b)
      let fpi = if fp == int then "0" else fp
-         vf = (pow b e) * (fromInteger (readBaseInt b ip) + readBaseFrac b fpi)
-         vi = (powi b e) * (readBaseInt b ip)
-     if (fp == int && e >= 0)
+         vf = pow b e * (fromInteger (readBaseInt b ip) + readBaseFrac b fpi)
+         vi = powi b e * readBaseInt b ip
+     if fp == int && e >= 0
         then return (IntNumber (if s == '-' then (-vi) else vi))
         else return (FltNumber (if s == '-' then (-vf) else vf))
 
@@ -253,7 +254,7 @@
                        else if ns < 0
                             then myRatNInf
                             else myRatNaN
-     if (denominator val) == 1
+     if denominator val == 1
         then return (IntNumber (numerator val))
         else return (RatNumber val)
 
@@ -261,18 +262,19 @@
 
 parseNaNInf :: Parser LispVal
 parseNaNInf =
-  do val <- (TPCP.try (string "+nan.0"))
-        <|> (TPCP.try (string "-nan.0"))
-        <|> (TPCP.try (string "+inf.0"))
-        <|> (TPCP.try (string "-inf.0"))
+  do val <- TPCP.try (string "+nan.0")
+        <|> TPCP.try (string "-nan.0")
+        <|> TPCP.try (string "+inf.0")
+        <|> TPCP.try (string "-inf.0")
      case val of
-          "+nan.0"    -> return (FltNumber myFltNaN)
-          "-nan.0"    -> return (FltNumber myFltNaN)
-          "+inf.0"    -> return (FltNumber myFltPInf)
-          "-inf.0"    -> return (FltNumber myFltNInf)
+          "+nan.0" -> return (FltNumber myFltNaN)
+          "-nan.0" -> return (FltNumber myFltNaN)
+          "+inf.0" -> return (FltNumber myFltPInf)
+          "-inf.0" -> return (FltNumber myFltNInf)
+          _ -> progError "parseNaNInf"
 
 parseNumber :: Parser LispVal
-parseNumber = (TPCP.try parseNaNInf) <|> (TPCP.try parseRat) <|> parseIntOrFlt
+parseNumber = TPCP.try parseNaNInf <|> TPCP.try parseRat <|> parseIntOrFlt
 
 -- Parsers for the abbreviations for the various kinds of quoting entities:
 --	'<datum>   =>  (quote <datum>)
@@ -306,9 +308,9 @@
      return (List [Symbol "unquote-splicing", x])
 
 parseQuoted :: Parser LispVal
-parseQuoted = (TPCP.try parseUQS)
-          <|> (TPCP.try parseUQ)
-          <|> (TPCP.try parseQQ)
+parseQuoted = TPCP.try parseUQS
+          <|> TPCP.try parseUQ
+          <|> TPCP.try parseQQ
           <|> parseQ
 
 -- Parser for a dotted-list or a regular list. Due to the representation of
@@ -327,21 +329,22 @@
      skipMany space
      char ')'
      if isl tl
-        then return (List (hd ++ (unpl tl)))
+        then return (List (hd ++ unpl tl))
         else if isdl tl
-                then return (DottedList (hd ++ (unpdlh tl)) (unpdlt tl))
+                then return (DottedList (hd ++ unpdlh tl) (unpdlt tl))
                 else return (DottedList hd tl)
   where isl (List ((Symbol sym):_)) =
-          if sym == "unquote" || sym == "unquote-splicing"
-             then False
-             else True
+          not (sym == "unquote" || sym == "unquote-splicing")
         isl (List _) = True
         isl _ = False
         unpl (List l) = l
+        unpl _ = progError "parseDottedList/unpl"
         isdl (DottedList _ _) = True
         isdl _ = False
         unpdlh (DottedList h _) = h
+        unpdlh _ = progError "parseDottedList/unpdlh"
         unpdlt (DottedList _ t) = t
+        unpdlt _ = progError "parseDottedList/unpdlt"
 
 -- Parser for a vector: this is similar to a list (but not a dotted-list),
 -- except that R6RS says access times are generally faster than for lists.
@@ -369,15 +372,15 @@
      return (Vector (toInteger (length vals))
                     (DIM.fromAscList (addkey 0 vals)))
   where addkey _ [] = []
-        addkey n (v:vs) = (n, v):(addkey (n+1) vs)
+        addkey n (v:vs) = (n, v) : addkey (n+1) vs
 
 parseExpr :: Parser LispVal
 parseExpr = parseString
-        <|> (TPCP.try parseBool)
-        <|> (TPCP.try parseChar)
-        <|> (TPCP.try parseNumber)
-        <|> (TPCP.try parseVector)
-        <|> (TPCP.try parseSymbol)
+        <|> TPCP.try parseBool
+        <|> TPCP.try parseChar
+        <|> TPCP.try parseNumber
+        <|> TPCP.try parseVector
+        <|> TPCP.try parseSymbol
         <|> parseQuoted
         <|> parseDottedList
 
@@ -392,8 +395,7 @@
 
 readExprList :: String -> ThrowsError [LispVal]
 readExprList =
-  readOrThrow ((optional hashbang) >>
-               (skipMany spaces) >>
+  readOrThrow (optional hashbang >> skipMany spaces >>
                endBy parseExpr (spaces <|> eof))
 
 -- Parser for just numbers, for internally converting strings to numbers;
diff --git a/WriteNumber.hs b/WriteNumber.hs
--- a/WriteNumber.hs
+++ b/WriteNumber.hs
@@ -18,8 +18,10 @@
 along with haskeem; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
-$Id: writenumber.hs,v 1.15 2009-08-06 05:05:15 uwe Exp $ -}
+$Id: writenumber.hs,v 1.18 2010-01-18 00:08:49 uwe Exp $ -}
 
+{-# LANGUAGE FlexibleContexts #-}
+
 module WriteNumber (writeNum, ilogb) where
 import Prelude
 import Numeric
@@ -39,6 +41,7 @@
 prefix 8 = "#o"
 prefix 10 = ""    -- implicit decimal, or "#d" if explicit prefix is desired
 prefix 16 = "#x"
+prefix _ = progError "writeNumber/prefix"
 
 -- Exponent marker for floating-point numbers in scientific notation:
 -- if we just use 'e' all the time, it makes base-16 numbers ambiguous,
@@ -57,7 +60,7 @@
           | otherwise = sign (n*d)
 
 d2c :: Int -> Char
-d2c d = ("0123456789abcdef" !! d)
+d2c = ("0123456789abcdef" !!)
 
 shi :: Integer -> Integer -> String
 shi b n = showIntAtBase b d2c n ""
@@ -68,7 +71,7 @@
 ilogb :: Integer -> Integer -> Integer
 ilogb b n | n < 0      = ilogb b (- n)
           | n < b      = 0
-          | otherwise  = (up 1) - 1
+          | otherwise  = up 1 - 1
   where up a = if n < (b ^ a)
                   then bin (quot a 2) a
                   else up (2*a)
@@ -87,24 +90,25 @@
 writeInt :: Integer -> Integer -> Maybe Integer -> String
 writeInt n b p =
   let pval = fromJust p
-      nval = (shi b (abs n))
-      hdr = (prefix b) ++ (sign n)
+      nval = shi b (abs n)
+      hdr = prefix b ++ sign n
   in if isNothing p
         then hdr ++ nval
         else if pval >= 0
-                then hdr ++ nval ++ "." ++ (replicate (fromInteger pval) '0')
+                then hdr ++ nval ++ "." ++ replicate (fromInteger pval) '0'
                 else writeRatE (fromInteger n) b (-pval)
 
 -- The non-finite rationals get treated specially: they get written
 -- in rational format regardless of whether we specified a precision
 
 isSpRat :: Rational -> Bool
-isSpRat n = (n == myRatNaN) || (n == myRatPInf) || (n == myRatNInf)
+isSpRat n = n == myRatNaN || n == myRatPInf || n == myRatNInf
 
-writeSpRat :: Rational -> [Char]
+writeSpRat :: Rational -> String
 writeSpRat n | n == myRatNaN    = "0/0"
              | n == myRatPInf   = "1/0"
              | n == myRatNInf   = "-1/0"
+             | otherwise        = progError "writeNumber/SpRat"
 
 -- this is pretty complicated, but it's all pure, and because haskell
 -- is lazy only those parts which are needed will get evaluated
@@ -122,19 +126,19 @@
       nf = nr * pfrac
       (nj, ns) = quotRem nf ad
       nt = 2*ns
-      ng = if (nt < ad) || ((nt == ad) && (even nj)) then nj else nj + 1
+      ng = if nt < ad || (nt == ad && even nj) then nj else nj + 1
       (carry, remder) = quotRem ng pfrac
       intp = shi b (ni + carry)
       fnz = shi b remder
-      len = fromInteger (pval - (toInteger (length fnz)))
-      fracp = (replicate len '0') ++ fnz
-      hdr = (prefix b) ++ (sign2 n d)
+      len = fromInteger (pval - toInteger (length fnz))
+      fracp = replicate len '0' ++ fnz
+      hdr = prefix b ++ sign2 n d
   in if isNothing p
-        then hdr ++ (shi b an) ++ "/" ++ (shi b ad)
+        then hdr ++ shi b an ++ "/" ++ shi b ad
         else if pval > 0
                 then hdr ++ intp  ++ "." ++ fracp
                 else if pval == 0
-                        then hdr ++ (shi b (round nval)) ++ "."
+                        then hdr ++ shi b (round nval) ++ "."
                         else writeRatE num b (-pval)
 
 -- Normalize a rational number n such that it's in the half-open interval
@@ -146,12 +150,12 @@
 normTo n b =
   let iln = ilogb 2 (numerator n)
       ild = ilogb 2 (denominator n)
-      lb0 = (fromInteger (iln - ild))/(logBase 2.0 (fromInteger b))
-      lb1 = toInteger (floor lb0)
+      lb0 = fromInteger (iln - ild) / logBase 2.0 (fromInteger b) :: Double
+      lb1 = floor lb0
       rb = fromInteger b
       sn1 = if lb1 >= 0
-               then (n / (fromInteger (b ^ lb1)))
-               else (n * (fromInteger (b ^ (-lb1))))
+               then n / fromInteger (b ^ lb1)
+               else n * fromInteger (b ^ (-lb1))
       (sn2, lb2) = if sn1 >= 1
                       then (sn1, lb1)
                       else (sn1 * rb, lb1 - 1)
@@ -162,17 +166,17 @@
 writeRatE :: Rational -> Integer -> Integer -> String
 writeRatE num b p =
   let (sn, se) = normTo (abs num) b
-      snr = sn/(fromInteger b)
+      snr = sn / fromInteger b
       ser = se+1
-      str = (writeRatF ((signum num)*sn) b (Just (abs p))) ++ (ssuf se)
-      strr = (writeRatF ((signum num)*snr) b (Just (abs p))) ++ (ssuf ser)
+      str = writeRatF (sn * signum num) b (Just (abs p)) ++ ssuf se
+      strr = writeRatF (snr * signum num) b (Just (abs p)) ++ ssuf ser
   in if num == 0
-        then (writeRatF (0%1) b (Just (abs p))) ++ (ssuf 0)
+        then writeRatF (0%1) b (Just (abs p)) ++ ssuf 0
         else if noround str
                 then str
                 else strr
-  where ssuf e = (emark b) ++ (sign e) ++ (shi b (abs e))
-        noround s = chek (takeWhile (/= '.') s)
+  where ssuf e = emark b ++ sign e ++ shi b (abs e)
+        noround = chek . takeWhile (/= '.')
         chek ('#':_:rest) = chek rest
         chek ('-':rest) = chek rest
         chek "10" = False
@@ -181,7 +185,7 @@
 -- The non-finite floating-point numbers get treated specially.
 
 isSpFlt :: RealFloat a => a -> Bool
-isSpFlt n = (isNaN n) || (isInfinite n)
+isSpFlt n = isNaN n || isInfinite n
 
 writeSpFlt :: RealFloat a => a -> String
 writeSpFlt n | n > 0       = "+inf.0"
@@ -191,62 +195,55 @@
 showFltAtBase :: Integer -> Double -> String
 showFltAtBase b x =
   let ((f:r),e) = floatToDigits b x
-  in (d2c f):("." ++ (map d2c r) ++ (emark b) ++
-     (sign (e - 1)) ++ (shi b (toInteger (abs (e - 1)))))
+  in d2c f : ("." ++ map d2c r ++ emark b ++
+     sign (e - 1) ++ shi b (toInteger (abs (e - 1))))
 
 writeFlt :: Double -> Integer -> Maybe Integer -> String
 writeFlt n b p =
   if isNothing p
-     then (prefix b) ++ (sign n) ++ (showFltAtBase b (abs n))
+     then prefix b ++ sign n ++ showFltAtBase b (abs n)
      else writeRatF (toRational n) b p
 
 goodBase :: Integer -> Bool
-goodBase b = (b == 2 || b == 8 || b == 10 || b == 16)
+goodBase b = b == 2 || b == 8 || b == 10 || b == 16
 
+badBase :: MonadError LispError m => Integer -> m b
 badBase b =
-  throwError (Default ("bad base " ++ (show b) ++ " in number->string"))
+  throwError (Default ("bad base " ++ show b ++ " in number->string"))
 
-writeNum :: [LispVal] -> ThrowsError LispVal
+rStr :: Monad m => String -> m LispVal
+rStr = return . String
 
-writeNum [IntNumber n] = return (String (writeInt n 10 Nothing))
-writeNum [IntNumber n, IntNumber b] =
-  if goodBase b
-     then return (String (writeInt n b Nothing))
-     else badBase b
-writeNum [IntNumber n, IntNumber b, IntNumber p] =
-  if goodBase b
-     then return (String (writeInt n b (Just p)))
-     else badBase b
+wrI :: MonadError LispError m =>
+  Integer -> Integer -> Maybe Integer -> m LispVal
+wrI n b p = if goodBase b then rStr (writeInt n b p) else badBase b
 
-writeNum [RatNumber n] = writeNum [RatNumber n, IntNumber 10]
-writeNum [RatNumber n, IntNumber b] =
-  if isSpRat n
-     then return (String (writeSpRat n))
-     else if goodBase b
-             then return (String (writeRatF n b Nothing))
-             else badBase b
-writeNum [RatNumber n, IntNumber b, IntNumber p] =
-  if isSpRat n
-     then return (String (writeSpRat n))
-     else if goodBase b
-             then return (String (writeRatF n b (Just p)))
-             else badBase b
+wrR :: MonadError LispError m =>
+  Rational -> Integer -> Maybe Integer -> m LispVal
+wrR n b p | isSpRat n    = rStr (writeSpRat n)
+          | goodBase b   = rStr (writeRatF n b p)
+          | otherwise    = badBase b
 
-writeNum [FltNumber n] = writeNum [FltNumber n, IntNumber 10]
-writeNum [FltNumber n, IntNumber b] =
-  if isSpFlt n
-     then return (String (writeSpFlt n))
-     else if goodBase b
-             then return (String (writeFlt n b Nothing))
-             else badBase b
-writeNum [FltNumber n, IntNumber b, IntNumber p] =
-  if isSpFlt n
-     then return (String (writeSpFlt n))
-     else if goodBase b
-             then return (String (writeFlt n b (Just p)))
-             else badBase b
+wrF :: MonadError LispError m =>
+  Double -> Integer -> Maybe Integer -> m LispVal
+wrF n b p | isSpFlt n    = rStr (writeSpFlt n)
+          | goodBase b   = rStr (writeFlt n b p)
+          | otherwise    = badBase b
 
+writeNum :: [LispVal] -> ThrowsError LispVal
+writeNum [IntNumber n]                           = wrI n 10 Nothing
+writeNum [IntNumber n, IntNumber b]              = wrI n b Nothing
+writeNum [IntNumber n, IntNumber b, IntNumber p] = wrI n b (Just p)
+
+writeNum [RatNumber n]                           = wrR n 10 Nothing
+writeNum [RatNumber n, IntNumber b]              = wrR n b Nothing
+writeNum [RatNumber n, IntNumber b, IntNumber p] = wrR n b (Just p)
+
+writeNum [FltNumber n]                           = wrF n 10 Nothing
+writeNum [FltNumber n, IntNumber b]              = wrF n b Nothing
+writeNum [FltNumber n, IntNumber b, IntNumber p] = wrF n b (Just p)
+
 writeNum badArgList =
   if length badArgList <= 3
-     then throwError (TypeMismatch "number->string" "number" (badArgList !! 0))
+     then throwError (TypeMismatch "number->string" "number" (head badArgList))
      else throwError (NumArgs "number->string" 3 badArgList)
diff --git a/delTEST.scm b/delTEST.scm
deleted file mode 100644
--- a/delTEST.scm
+++ /dev/null
@@ -1,642 +0,0 @@
-; (load "delcont.scm")
-
-(defmacro (sandbox . expr)
-  (let ((err (gensym)))
-    `(guard
-      (,err ((begin (write-string "caught exception '")
-		    (display ,err)
-		    (write-string "'\n")
-		    #t)))
-      ,@expr)))
-
-; for mzscheme, replace the above definition of sandbox with
-;	(define (sandbox . expr) #t)
-; it won't catch exceptions, but then mzscheme doesn't produce
-; any, except for the intentional syntax error at the end
-
-(write-string "all answers are checked against mzscheme\n")
-
-(write-string "examples from community.schemewiki.org\n")
-
-(write-string "r  should be 6\t\t")
-(sandbox
- (display (+ 1 (RESET (+ 2 3))))
- (newline))
-
-(write-string "r  should be (1 2)\t")
-(sandbox
- (display (cons 1 (RESET (cons 2 '()))))
- (newline))
-
-(write-string "r  should be 4\t\t")
-(sandbox
- (display (+ 1 (RESET (+ 2 (SHIFT k 3)))))
- (newline))
-
-(write-string "r  should be (1 3)\t")
-(sandbox
- (display (cons 1 (RESET (cons 2 (SHIFT k (cons 3 '()))))))
- (newline))
-
-(write-string "r  should be 10\t\t")
-(sandbox
- (display (+ 1 (RESET (+ 2 (SHIFT k (+ 3 (k 4)))))))
- (newline))
-
-(write-string "r  should be 14\t\t")
-(sandbox
- (display (+ 1 (RESET (+ 2 (SHIFT k (+ 3 (k 5) (k 1)))))))
- (newline))
-
-(write-string "r  should be (1 3 2 4)\t")
-(sandbox
- (display (cons 1 (RESET (cons 2 (SHIFT k (cons 3 (k (cons 4 '()))))))))
- (newline))
-
-(write-string "r  should be (1 3 2 2 4)\t")
-(sandbox
- (display (cons 1 (RESET (cons 2 (SHIFT k (cons 3 (k (k (cons 4 '())))))))))
- (newline))
-
-(write-string "multiple SHIFTs\n")
-
-(write-string "r  should be 2\t\t")
-(sandbox
- (RESET (display (begin (SHIFT k1 (k1 1)) (SHIFT k2 (k2 2)))))
- (newline))
-
-; haskeem fails this -- restart issue
-(write-string "r  should be 12\t\t")
-(sandbox
- (RESET (begin (display (SHIFT k1 (k1 1))) (display (SHIFT k2 (k2 2)))))
- (newline))
-
-(write-string "r  should be 12\t\t")
-(sandbox
- (RESET (display (SHIFT k1 (k1 1))) (display (SHIFT k2 (k2 2))))
- (newline))
-
-(write-string "r0 should be 134234\t")
-(sandbox
- (RESET0 (begin (SHIFT0 k1 (begin (k1 (display 1)) (k1 (display 2))))
-		(SHIFT0 k2 (begin (k2 (display 3)) (k2 (display 4))))))
- (newline))
-
-(write-string "r0 should be 134234\t")
-(sandbox
- (RESET0 (begin (SHIFT0 k1 (k1 (display 1)) (k1 (display 2)))
-		(SHIFT0 k2 (k2 (display 3)) (k2 (display 4)))))
- (newline))
-
-(write-string "r0 should be 134234\t")
-(sandbox
- (RESET0 (SHIFT0 k1 (k1 (display 1)) (k1 (display 2)))
-	 (SHIFT0 k2 (k2 (display 3)) (k2 (display 4))))
- (newline))
-
-(write-string "r0 should be 13564562356456\n\t     ")
-(sandbox
- (RESET0 (begin (SHIFT0 k1 (begin (k1 (display 1)) (k1 (display 2))))
-		(SHIFT0 k2 (begin (k2 (display 3)) (k2 (display 4))))
-		(SHIFT0 k3 (begin (k3 (display 5)) (k3 (display 6))))))
- (write-string "\n\t     ")
- (RESET0 (begin (SHIFT0 k1 (k1 (display 1)) (k1 (display 2)))
-		(SHIFT0 k2 (k2 (display 3)) (k2 (display 4)))
-		(SHIFT0 k3 (k3 (display 5)) (k3 (display 6)))))
- (write-string "\n\t     ")
- (RESET0 (SHIFT0 k1 (k1 (display 1)) (k1 (display 2)))
-	 (SHIFT0 k2 (k2 (display 3)) (k2 (display 4)))
-	 (SHIFT0 k3 (k3 (display 5)) (k3 (display 6))))
- (newline))
-
-(write-string "r  should be 57\t\t")
-(sandbox
- (display (+ 1 (RESET (+ 2 (SHIFT k1 (+ 3
-					(k1 5)
-					(k1 1)
-					(RESET (* 10 (SHIFT k2 (+ 3 (k2 4)))))
-					))))))
- (newline))
-
-(write-string "r  should be 59\t\t")
-(sandbox
- (display (+ 1 (RESET (+ 2 (SHIFT k1 (+ 3
-					(k1 5)
-					(k1 1)
-					(RESET (* 10 (SHIFT k2 (+ (k1 3)
-								  (k2 4)))))
-					))))))
- (newline))
-
-; haskeem fails the following nine -- restart issue
-
-(write-string "r  should be 1 3 2\t")
-(sandbox
- (RESET (begin (write-string "1 ")
-	       (SHIFT c (begin (c 'ignore)
-			       (write-string "2 ")))
-	       (write-string "3 ")))
- (newline))
-(write-string "r  should be 1 3 2\t")
-(sandbox
- (RESET (begin (write-string "1 ")
-	       (SHIFT c (c 'ignore) (write-string "2 "))
-	       (write-string "3 ")))
- (newline))
-(write-string "r  should be 1 3 2\t")
-(sandbox
- (RESET (write-string "1 ")
-	(SHIFT c (c 'ignore) (write-string "2 "))
-	(write-string "3 "))
- (newline))
-
-(write-string "r  should be 1 2 3\t")
-(sandbox
- (RESET (begin (write-string "1 ")
-	       (SHIFT c (begin (write-string "2 ")
-			       (c 'ignore)))
-	       (write-string "3 ")))
- (newline))
-(write-string "r  should be 1 2 3\t")
-(sandbox
- (RESET (begin (write-string "1 ")
-	       (SHIFT c (write-string "2 ") (c 'ignore))
-	       (write-string "3 ")))
- (newline))
-(write-string "r  should be 1 2 3\t")
-(sandbox
- (RESET (write-string "1 ")
-	(SHIFT c (write-string "2 ") (c 'ignore))
-	(write-string "3 "))
- (newline))
-
-(write-string "r  should be 1 3 2 3\t")
-(sandbox
- (RESET (begin (write-string "1 ")
-	       (SHIFT c (begin (c 'ignore)
-			       (write-string "2 ")
-			       (c 'ignore)))
-	       (write-string "3 ")))
- (newline))
-(write-string "r  should be 1 3 2 3\t")
-(sandbox
- (RESET (begin (write-string "1 ")
-	       (SHIFT c (c 'ignore) (write-string "2 ") (c 'ignore))
-	       (write-string "3 ")))
- (newline))
-(write-string "r  should be 1 3 2 3\t")
-(sandbox
- (RESET (write-string "1 ")
-	(SHIFT c (c 'ignore) (write-string "2 ") (c 'ignore))
-	(write-string "3 "))
- (newline))
-
-(write-string "from Shan, \"Shift to Control\"\n")
-
-(write-string "r  should be (a)\t")
-(sandbox
- (display (RESET (cons 'a (RESET (SHIFT f (SHIFT g '()))))))
- (newline))
-
-(write-string "r0 should be ()\t\t")
-(sandbox
- (display (RESET0 (cons 'a (RESET0 (SHIFT0 f (SHIFT0 g '()))))))
- (newline))
-
-(write-string "r  should be (a)\t")
-(sandbox
- (display (RESET (let ((y (SHIFT f (cons 'a (f '()))))) (SHIFT g y))))
- (newline))
-
-(write-string "p  should be ()\t\t")
-(sandbox
- (display (PROMPT (let ((y (CONTROL f (cons 'a (f '()))))) (CONTROL g y))))
- (newline))
-
-; Shan sez this is an infinite loop... Kiselyov turns this into a printing
-; loop by adding (display) somewhere, have to see if I can replicate that.
-; I dunno if the name has to be 'f' in both CONTROL parts
-
-;(PROMPT (begin (CONTROL f (begin (f 0) (f 0)))
-;	       (CONTROL f (begin (f 0) (f 0)))))
-
-;;;(write-string "should be 132342344234442344442344444234444442344...\n\t  ")
-;;; with RESET2 it /is/ an infinite loop, just not the desired one...
-;;; it produces 1313131313... instead
-;;; I think this is actually the same partially-evaluated-thunk issue
-;;; as with the other tests which are failing
-;;;(PROMPT (begin (CONTROL f (begin (f (display 1)) (f (display 2))))
-;;;	      (CONTROL f (begin (f (display 3)) (f (display 4))))))
-;;;(newline)
-
-(write-string "r  should be (a)\t")
-(sandbox
- (display (RESET (let ((y (SHIFT f (cons 'a (f '()))))) (SHIFT g y))))
- (newline))
-
-(write-string "r0 should be (a)\t")
-(sandbox
- (display (RESET0 (let ((y (SHIFT0 f (cons 'a (f '()))))) (SHIFT0 g y))))
- (newline))
-
-(write-string "p  should be ()\t\t")
-(sandbox
- (display (PROMPT (let ((y (CONTROL f (cons 'a (f '()))))) (CONTROL g y))))
- (newline))
-
-(write-string "p0 should be ()\t\t")
-(sandbox
- (display
-  (RESET (PROMPT0 (let ((y (CONTROL0 f (cons 'a (f '()))))) (CONTROL0 g y)))))
- (newline))
-
-(write-string "r  should be (a b)\t")
-(sandbox
- (display
-  (RESET
-   (RESET (cons 'a (RESET
-		    (let ((y (SHIFT f (SHIFT g (cons 'b (f '()))))))
-		      (SHIFT h y)))))))
- (newline))
-
-(write-string "p  should be (a)\t")
-(sandbox
- (display
-  (PROMPT
-   (PROMPT (cons 'a (PROMPT
-		     (let ((y (CONTROL f (CONTROL g (cons 'b (f '()))))))
-		       (CONTROL h y)))))))
- (newline))
-
-(write-string "r0 should be (b)\t")
-(sandbox
- (display
-  (RESET0
-   (RESET0 (cons 'a (RESET0
-		     (let ((y (SHIFT0 f (SHIFT0 g (cons 'b (f '()))))))
-		       (SHIFT0 h y)))))))
- (newline))
-
-; haskeem fails this -- UNKNOWN ISSUE! TODO: investigate!
-
-(write-string "p0 should be ()\t\t")
-(sandbox
- (display
-  (PROMPT0
-   (PROMPT0 (cons 'a (PROMPT0
-		      (let ((y (CONTROL0 f (CONTROL0 g (cons 'b (f '()))))))
-			(CONTROL0 h y)))))))
- (newline))
-
-(write-string "two-armed tests\n")
-(write-string "test 1: non-trivial SHIFT only in false arm of if\n")
-(define (doit1 flag)
-  (if flag
-      (write-string "r  should be (1 3)\t")
-      (write-string "r  should be (1 4 2 5)\t"))
-  (sandbox
-   (display
-    (cons 1 (RESET (cons 2 (if flag
-			       (SHIFT k1 (cons 3 '()))
-			       (SHIFT k2 (cons 4 (k2 (cons 5 '())))))))))
-   (newline)))
-
-(doit1 #f)
-(doit1 #t)
-
-(write-string "test 2: reverse of previous\n")
-(define (doit2 flag)
-  (if flag
-      (write-string "r  should be (1 4 2 5)\t")
-      (write-string "r  should be (1 3)\t"))
-  (sandbox
-   (display
-    (cons 1 (RESET (cons 2 (if flag
-			       (SHIFT k2 (cons 4 (k2 (cons 5 '()))))
-			       (SHIFT k1 (cons 3 '())))))))
-   (newline)))
-
-(doit2 #f)
-(doit2 #t)
-
-(write-string "test 3: wrong? expansion of test 1\n")
-
-(define (doit3 flag)
-  (write-string "r  should be (1 4 3)\t")	; independent of flag
-  (sandbox
-   (display
-    (cons 1
-	  (let ((k2 (lambda (v2)
-		      (let ((k1 (lambda (v1)
-				  (RESET (cons 2 (if flag v1 v2))))))
-			(cons 3 '())))))
-	    (RESET (cons 4 (k2 (cons 5 '())))))))
-   (newline)))
-
-(doit3 #f)
-(doit3 #t)
-
-(write-string "test 4: expansion of test 2\n")
-(define (doit4 flag)
-  (if flag
-      (write-string "r  should be (1 4 2 3)\t")
-      (write-string "r  should be (1 4 2 5)\t"))
-  (sandbox
-   (display
-    (cons 1
-	  (let ((k2 (lambda (v2)
-		      (RESET (cons 2 (if flag (cons 3 '()) v2))))))
-	    (RESET (cons 4 (k2 (cons 5 '())))))))
-   (newline)))
-
-(doit4 #f)
-(doit4 #t)
-
-(write-string "test 5: modified version, with (SHIFT) in both arms of (if)\n")
-(define (doit5 flag)
-  (if flag
-      (write-string "r  should be (1 3 2 4)\t")
-      (write-string "r  should be (1 5 2 6)\t"))
-  (sandbox
-   (display
-    (cons 1
-	  (RESET (cons 2 (if flag
-			     (SHIFT k1 (cons 3 (k1 (cons 4 '()))))
-			     (SHIFT k2 (cons 5 (k2 (cons 6 '())))))))))
-   (newline)))
-
-(doit5 #f)
-(doit5 #t)
-
-(write-string
- "test 6: modified version of test 5, with (if) lifted out of (RESET)\n")
-
-(define (doit6 flag)
-  (if flag
-      (write-string "r  should be (1 3 2 4)\t")
-      (write-string "r  should be (1 5 2 6)\t"))
-  (sandbox
-   (display
-    (cons 1
-	  (if flag
-	      (RESET (cons 2 (SHIFT k1 (cons 3 (k1 (cons 4 '()))))))
-	      (RESET (cons 2 (SHIFT k2 (cons 5 (k2 (cons 6 '())))))))))
-   (newline)))
-
-(doit6 #f)
-(doit6 #t)
-
-(write-string "examples from Queinnec, augmented to test all versions\n")
-
-(write-string "PROMPT/CONTROL examples\n")
-(write-string "should be 3\t\t")
-(sandbox
- (display (PROMPT (* 2 (CONTROL f 3))))
- (newline))
-
-(write-string "should be 30\t\t")
-(sandbox
- (display (PROMPT (* 2 (CONTROL f (* 5 (f 3))))))
- (newline))
-
-(write-string "should be 12\t\t")
-(sandbox
- (display (PROMPT (* 2 (CONTROL f (f (f 3))))))
- (newline))
-
-(write-string "should be 6\t\t")
-(sandbox
- (display ((PROMPT (* 2 (CONTROL f f))) 3))
- (newline))
-
-(write-string "should be 35\t\t")
-(sandbox
- (display (PROMPT (* 5
-		     (PROMPT (* 2
-				(CONTROL f2 (* 3 (CONTROL f3 7))))))))
- (newline))
-
-; haskeem quasi-fails this: because it's a (lambda () ...), it escapes,
-; and so at the end there's an uncaught exception which however carries
-; along the correct value as its payload. So I think haskeem would handle
-; this correctly if there were an implicit top-level catcher
-
-(write-string "should be 7\t\t")
-(sandbox
- (display (PROMPT (* 5 (
-			(PROMPT (* 2
-				   (CONTROL f2 (lambda ()
-						 (* 3 (CONTROL f3 7))))))))))
- (newline))
-
-(write-string "should be 21\t\t")
-(sandbox
- (display (PROMPT (* 5
-		     ((lambda (x) (CONTROL f1 x))
-		      (* 3 (CONTROL f2 (* 2 (f2 7))))))))
- (newline))
-
-(write-string "PROMPT0/CONTROL0 examples\n")
-(write-string "should be 3\t\t")
-(sandbox
- (display (PROMPT0 (* 2 (CONTROL0 f 3))))
- (newline))
-
-(write-string "should be 30\t\t")
-(sandbox
- (display (PROMPT0 (* 2 (CONTROL0 f (* 5 (f 3))))))
- (newline))
-
-(write-string "should be 12\t\t")
-(sandbox
- (display (PROMPT0 (* 2 (CONTROL0 f (f (f 3))))))
- (newline))
-
-(write-string "should be 6\t\t")
-(sandbox
- (display ((PROMPT0 (* 2 (CONTROL0 f f))) 3))
- (newline))
-
-(write-string "should be 7\t\t")
-(sandbox
- (display (PROMPT0 (* 5
-		      (PROMPT0 (* 2
-				  (CONTROL0 f2 (* 3 (CONTROL0 f3 7))))))))
- (newline))
-
-(write-string "should be 7\t\t")
-(sandbox
- (display (PROMPT0 (* 5 (
-			(PROMPT0 (* 2
-				   (CONTROL0 f2 (lambda ()
-						 (* 3 (CONTROL0 f3 7))))))))))
- (newline))
-
-; There's something odd with this test: in mzscheme, it prints the
-; result 21, then the whole rest of the test vanishes; apparently
-; enough of the surrounding context is sucked up that the rest of the
-; world just vanishes. If I surround this with a (RESET ...), the
-; test continues, but this doesn't print anything. Hmmm!
-
-(write-string "should be 21\t\t")
-(sandbox
- (display (PROMPT0 (* 5
-		      ((lambda (x) (CONTROL0 f1 x))
-		       (* 3 (CONTROL0 f2 (* 2 (f2 7))))))))
- (newline))
-
-(write-string "RESET/SHIFT examples\n")
-(write-string "should be 3\t\t")
-(sandbox
- (display (RESET (* 2 (SHIFT f 3))))
- (newline))
-
-(write-string "should be 30\t\t")
-(sandbox
- (display (RESET (* 2 (SHIFT f (* 5 (f 3))))))
- (newline))
-
-(write-string "should be 12\t\t")
-(sandbox
- (display (RESET (* 2 (SHIFT f (f (f 3))))))
- (newline))
-
-(write-string "should be 6\t\t")
-(sandbox
- (display ((RESET (* 2 (SHIFT f f))) 3))
- (newline))
-
-(write-string "should be 35\t\t")
-(sandbox
- (display (RESET (* 5
-		    (RESET (* 2
-			      (SHIFT f2 (* 3 (SHIFT f3 7))))))))
- (newline))
-
-(write-string "should be 7\t\t")
-(sandbox
- (display (RESET (* 5 (
-		       (RESET (* 2
-				 (SHIFT f2 (lambda ()
-					     (* 3 (SHIFT f3 7))))))))))
- (newline))
-
-(write-string "should be 42\t\t")
-(sandbox
- (display (RESET (* 5
-		    ((lambda (x) (SHIFT f1 x))
-		     (* 3 (SHIFT f2 (* 2 (f2 7))))))))
- (newline))
-
-(write-string "RESET0/SHIFT0 examples\n")
-(write-string "should be 3\t\t")
-(sandbox
- (display (RESET0 (* 2 (SHIFT0 f 3))))
- (newline))
-
-(write-string "should be 30\t\t")
-(sandbox
- (display (RESET0 (* 2 (SHIFT0 f (* 5 (f 3))))))
- (newline))
-
-(write-string "should be 12\t\t")
-(sandbox
- (display (RESET0 (* 2 (SHIFT0 f (f (f 3))))))
- (newline))
-
-(write-string "should be 6\t\t")
-(sandbox
- (display ((RESET0 (* 2 (SHIFT0 f f))) 3))
- (newline))
-
-(write-string "should be 7\t\t")
-(sandbox
- (display (RESET0 (* 5
-		     (RESET0 (* 2
-				(SHIFT0 f2 (* 3 (SHIFT0 f3 7))))))))
- (newline))
-
-(write-string "should be 7\t\t")
-(sandbox
- (display (RESET0 (* 5 (
-		       (RESET0 (* 2
-				 (SHIFT0 f2 (lambda ()
-					     (* 3 (SHIFT0 f3 7))))))))))
- (newline))
-
-(write-string "should be 42\t\t")
-(sandbox
- (display (RESET0 (* 5
-		     ((lambda (x) (SHIFT0 f1 x))
-		      (* 3 (SHIFT0 f2 (* 2 (f2 7))))))))
- (newline))
-
-(write-string "r  something actually useful! a small table of factorials\n")
-
-; Eventually we want to be able to use code like this:
-
-; (defmacro (range from step to)
-;   (let ((f (gensym))
-;	(i (gensym)))
-;     `(SHIFT ,f
-;	    (do ((,i ,from (+ ,i ,step)))
-;		((> ,i ,to) #f)
-;	      (,f ,i)))))
-;
-; (RESET (begin (display (my-fact (range 1 3 16))) (newline)))
-
-; Just to show I've got nothing up my sleeve, here is a perfectly cromulent
-; function; we could equally well use the built-in (factorial) function
-
-(define (my-fact n)
-  (if (<= n 0)
-      1
-      (* n (my-fact (- n 1)))))
-
-(define from 1)
-(define to 21)
-(define step 3)
-
-(sandbox
- (RESET (display (my-fact 
-		  (SHIFT f
-			 (do ((i from (+ i step)))
-			     ((> i to) #f)
-			   (write-string (number->string i))
-			   (write-string "! =\t")
-			   (f i)))))
-	(newline)))
-
-; This one is specific to haskeem, because the macro RESET doesn't start
-; the thunk in the middle, but rather at the beginning; that makes the
-; ping-pong possible
-
-(write-string
- "These rely on the RESET thunk being re-evaluated from the beginning,\n")
-(write-string
- "so strictly speaking both are wrong. So I don't know what the answers\n")
-(write-string
- "\"should be\"... but they look plausible\n")
-(define (doit7 flag)
-  (sandbox
-   (display
-    (cons 1
-	  (RESET (cons 2 (if flag
-			     (SHIFT k1 (set! flag (not flag))
-				    (cons 3 (k1 (cons 4 '()))))
-			     (SHIFT k2 (set! flag (not flag))
-				    (cons 5 (k2 (cons 6 '())))))))))
-   (newline)))
-
-; it's hard to say if these are right... both rely on a wrong implementation
-; of the thunk stuff
-
-(doit7 #f)	; (1 5 3 2 6) -- mzscheme sez (1 5 2 6)
-(doit7 #t)	; (1 3 5 2 4) -- mzscheme sez (1 3 2 4)
-
-(write-string
- "syntax error coming up! should be an error... this'll kill mzscheme\n")
-
-(sandbox (display (+ 1 (RESET (+ 2 (SHIFT (+ k 1) 3))))))
-(write-string
- "haskeem should have caught the exception raised by the syntax error\n")
diff --git a/delcont.scm b/delcont.scm
--- a/delcont.scm
+++ b/delcont.scm
@@ -1,5 +1,5 @@
 ; Copyright 2009 Uwe Hollerbach <uh@alumni.caltech.edu>
-; $Id: delcont.scm,v 1.14 2009-08-02 03:18:24 uwe Exp $
+; $Id: delcont.scm,v 1.15 2009-08-09 05:38:50 uwe Exp $
 ; BSD3
 
 ; Delimited continuations: these look simpler than call/cc, just a fairly
@@ -30,9 +30,13 @@
 ; there are multiple args... gotta be a better way to do that?
 ; Still, this works and allows testing.
 
+; These are renamed to reset/m etc, all with trailing /m, to denote
+; that they're macros, and to not interfere with the native versions
+; of at least reset and shift.
+
 (define *delcont-list* '())
 
-(defmacro (reset . expr)
+(defmacro (reset/m . expr)
   (letrec* ((id (gensym))
 	    (ret (gensym))
 	    (err (gensym))
@@ -43,14 +47,14 @@
 	    (r-aux (lambda (ex)
 		     (cond ((not (list? ex)) ex)
 			   ((null? ex) ex)
-			   ((or (eqv? 'shift (car ex))
-				(eqv? 'shift0 (car ex))
-				(eqv? 'control (car ex))
-				(eqv? 'control0 (car ex)))
-			    (let ((f1 (or (eqv? 'shift (car ex))
-					  (eqv? 'shift0 (car ex))))
-				  (f2 (or (eqv? 'shift (car ex))
-					  (eqv? 'control (car ex)))))
+			   ((or (eqv? 'shift/m (car ex))
+				(eqv? 'shift0/m (car ex))
+				(eqv? 'control/m (car ex))
+				(eqv? 'control0/m (car ex)))
+			    (let ((f1 (or (eqv? 'shift/m (car ex))
+					  (eqv? 'shift0/m (car ex))))
+				  (f2 (or (eqv? 'shift/m (car ex))
+					  (eqv? 'control/m (car ex)))))
 			      (set! flag #t)
 			      (if (and (> (length ex) 2)
 				       (symbol? (cadr ex)))
@@ -96,21 +100,21 @@
 
 ; aliases -- in this macro-based approach, they should be just sugar
 
-(define reset0 reset)
-(define prompt reset)
-(define prompt0 reset)
+(define reset0/m reset/m)
+(define prompt/m reset/m)
+(define prompt0/m reset/m)
 
 ; stupid-catchers
 
-(defmacro (shift sym expr)
-  (raise "oops, naked delcont form" 'shift sym expr))
+(defmacro (shift/m sym expr)
+  (raise "oops, naked delcont form" 'shift/m sym expr))
 
-(defmacro (shift0 sym expr)
-  (raise "oops, naked delcont form" 'shift0 sym expr))
+(defmacro (shift0/m sym expr)
+  (raise "oops, naked delcont form" 'shift0/m sym expr))
 
-(defmacro (control sym expr)
-  (raise "oops, naked delcont form" 'control sym expr))
+(defmacro (control/m sym expr)
+  (raise "oops, naked delcont form" 'control/m sym expr))
 
-(defmacro (control0 sym expr)
-  (raise "oops, naked delcont form" 'control0 sym expr))
+(defmacro (control0/m sym expr)
+  (raise "oops, naked delcont form" 'control0/m sym expr))
 
diff --git a/deltest.scm b/deltest.scm
--- a/deltest.scm
+++ b/deltest.scm
@@ -1,3 +1,8 @@
+; For the time being, comment out the reset0, prompt, and prompt0 examples:
+; there's something fairly fundamental missing in haskeem (but I don't know
+; what it is), so it doesn't handle these at all well. The reset/shift
+; examples are all correct, except for the restart issue.
+
 ; (load "delcont.scm")
 
 (defmacro (sandbox . expr)
@@ -18,98 +23,98 @@
 
 (write-string "examples from community.schemewiki.org\n")
 
-(write-string "r  should be 6\t\t")
+(write-string "should be 6\t\t")
 (sandbox
  (display (+ 1 (reset (+ 2 3))))
  (newline))
 
-(write-string "r  should be (1 2)\t")
+(write-string "should be (1 2)\t\t")
 (sandbox
  (display (cons 1 (reset (cons 2 '()))))
  (newline))
 
-(write-string "r  should be 4\t\t")
+(write-string "should be 4\t\t")
 (sandbox
  (display (+ 1 (reset (+ 2 (shift k 3)))))
  (newline))
 
-(write-string "r  should be (1 3)\t")
+(write-string "should be (1 3)\t\t")
 (sandbox
  (display (cons 1 (reset (cons 2 (shift k (cons 3 '()))))))
  (newline))
 
-(write-string "r  should be 10\t\t")
+(write-string "should be 10\t\t")
 (sandbox
  (display (+ 1 (reset (+ 2 (shift k (+ 3 (k 4)))))))
  (newline))
 
-(write-string "r  should be 14\t\t")
+(write-string "should be 14\t\t")
 (sandbox
  (display (+ 1 (reset (+ 2 (shift k (+ 3 (k 5) (k 1)))))))
  (newline))
 
-(write-string "r  should be (1 3 2 4)\t")
+(write-string "should be (1 3 2 4)\t")
 (sandbox
  (display (cons 1 (reset (cons 2 (shift k (cons 3 (k (cons 4 '()))))))))
  (newline))
 
-(write-string "r  should be (1 3 2 2 4)\t")
+(write-string "should be (1 3 2 2 4)\t")
 (sandbox
  (display (cons 1 (reset (cons 2 (shift k (cons 3 (k (k (cons 4 '())))))))))
  (newline))
 
 (write-string "multiple shifts\n")
 
-(write-string "r  should be 2\t\t")
+(write-string "should be 2\t\t")
 (sandbox
  (reset (display (begin (shift k1 (k1 1)) (shift k2 (k2 2)))))
  (newline))
 
 ; haskeem fails this -- restart issue
-(write-string "r  should be 12\t\t")
+(write-string "should be 12\t\t")
 (sandbox
  (reset (begin (display (shift k1 (k1 1))) (display (shift k2 (k2 2)))))
  (newline))
 
-(write-string "r  should be 12\t\t")
+(write-string "should be 12\t\t")
 (sandbox
  (reset (display (shift k1 (k1 1))) (display (shift k2 (k2 2))))
  (newline))
 
-(write-string "r0 should be 134234\t")
+(write-string "should be 134234\t")
 (sandbox
- (reset0 (begin (shift0 k1 (begin (k1 (display 1)) (k1 (display 2))))
-		(shift0 k2 (begin (k2 (display 3)) (k2 (display 4))))))
+ (reset (begin (shift k1 (begin (k1 (display 1)) (k1 (display 2))))
+	       (shift k2 (begin (k2 (display 3)) (k2 (display 4))))))
  (newline))
 
-(write-string "r0 should be 134234\t")
+(write-string "should be 134234\t")
 (sandbox
- (reset0 (begin (shift0 k1 (k1 (display 1)) (k1 (display 2)))
-		(shift0 k2 (k2 (display 3)) (k2 (display 4)))))
+ (reset (begin (shift k1 (k1 (display 1)) (k1 (display 2)))
+	       (shift k2 (k2 (display 3)) (k2 (display 4)))))
  (newline))
 
-(write-string "r0 should be 134234\t")
+(write-string "should be 134234\t")
 (sandbox
- (reset0 (shift0 k1 (k1 (display 1)) (k1 (display 2)))
-	 (shift0 k2 (k2 (display 3)) (k2 (display 4))))
+ (reset (shift k1 (k1 (display 1)) (k1 (display 2)))
+	(shift k2 (k2 (display 3)) (k2 (display 4))))
  (newline))
 
-(write-string "r0 should be 13564562356456\n\t     ")
+(write-string "should be 13564562356456\n\t  ")
 (sandbox
- (reset0 (begin (shift0 k1 (begin (k1 (display 1)) (k1 (display 2))))
-		(shift0 k2 (begin (k2 (display 3)) (k2 (display 4))))
-		(shift0 k3 (begin (k3 (display 5)) (k3 (display 6))))))
- (write-string "\n\t     ")
- (reset0 (begin (shift0 k1 (k1 (display 1)) (k1 (display 2)))
-		(shift0 k2 (k2 (display 3)) (k2 (display 4)))
-		(shift0 k3 (k3 (display 5)) (k3 (display 6)))))
- (write-string "\n\t     ")
- (reset0 (shift0 k1 (k1 (display 1)) (k1 (display 2)))
-	 (shift0 k2 (k2 (display 3)) (k2 (display 4)))
-	 (shift0 k3 (k3 (display 5)) (k3 (display 6))))
+ (reset (begin (shift k1 (begin (k1 (display 1)) (k1 (display 2))))
+	       (shift k2 (begin (k2 (display 3)) (k2 (display 4))))
+	       (shift k3 (begin (k3 (display 5)) (k3 (display 6))))))
+ (write-string "\n\t  ")
+ (reset (begin (shift k1 (k1 (display 1)) (k1 (display 2)))
+	       (shift k2 (k2 (display 3)) (k2 (display 4)))
+	       (shift k3 (k3 (display 5)) (k3 (display 6)))))
+ (write-string "\n\t  ")
+ (reset (shift k1 (k1 (display 1)) (k1 (display 2)))
+	(shift k2 (k2 (display 3)) (k2 (display 4)))
+	(shift k3 (k3 (display 5)) (k3 (display 6))))
  (newline))
 
-(write-string "r  should be 57\t\t")
+(write-string "should be 57\t\t")
 (sandbox
  (display (+ 1 (reset (+ 2 (shift k1 (+ 3
 					(k1 5)
@@ -118,7 +123,7 @@
 					))))))
  (newline))
 
-(write-string "r  should be 59\t\t")
+(write-string "should be 59\t\t")
 (sandbox
  (display (+ 1 (reset (+ 2 (shift k1 (+ 3
 					(k1 5)
@@ -130,47 +135,47 @@
 
 ; haskeem fails the following nine -- restart issue
 
-(write-string "r  should be 1 3 2\t")
+(write-string "should be 1 3 2\t\t")
 (sandbox
  (reset (begin (write-string "1 ")
 	       (shift c (begin (c 'ignore)
 			       (write-string "2 ")))
 	       (write-string "3 ")))
  (newline))
-(write-string "r  should be 1 3 2\t")
+(write-string "should be 1 3 2\t\t")
 (sandbox
  (reset (begin (write-string "1 ")
 	       (shift c (c 'ignore) (write-string "2 "))
 	       (write-string "3 ")))
  (newline))
-(write-string "r  should be 1 3 2\t")
+(write-string "should be 1 3 2\t\t")
 (sandbox
  (reset (write-string "1 ")
 	(shift c (c 'ignore) (write-string "2 "))
 	(write-string "3 "))
  (newline))
 
-(write-string "r  should be 1 2 3\t")
+(write-string "should be 1 2 3\t\t")
 (sandbox
  (reset (begin (write-string "1 ")
 	       (shift c (begin (write-string "2 ")
 			       (c 'ignore)))
 	       (write-string "3 ")))
  (newline))
-(write-string "r  should be 1 2 3\t")
+(write-string "should be 1 2 3\t\t")
 (sandbox
  (reset (begin (write-string "1 ")
 	       (shift c (write-string "2 ") (c 'ignore))
 	       (write-string "3 ")))
  (newline))
-(write-string "r  should be 1 2 3\t")
+(write-string "should be 1 2 3\t\t")
 (sandbox
  (reset (write-string "1 ")
 	(shift c (write-string "2 ") (c 'ignore))
 	(write-string "3 "))
  (newline))
 
-(write-string "r  should be 1 3 2 3\t")
+(write-string "should be 1 3 2 3\t")
 (sandbox
  (reset (begin (write-string "1 ")
 	       (shift c (begin (c 'ignore)
@@ -178,13 +183,13 @@
 			       (c 'ignore)))
 	       (write-string "3 ")))
  (newline))
-(write-string "r  should be 1 3 2 3\t")
+(write-string "should be 1 3 2 3\t")
 (sandbox
  (reset (begin (write-string "1 ")
 	       (shift c (c 'ignore) (write-string "2 ") (c 'ignore))
 	       (write-string "3 ")))
  (newline))
-(write-string "r  should be 1 3 2 3\t")
+(write-string "should be 1 3 2 3\t")
 (sandbox
  (reset (write-string "1 ")
 	(shift c (c 'ignore) (write-string "2 ") (c 'ignore))
@@ -193,32 +198,25 @@
 
 (write-string "from Shan, \"Shift to Control\"\n")
 
-(write-string "r  should be (a)\t")
+(write-string "should be (a)\t\t")
 (sandbox
  (display (reset (cons 'a (reset (shift f (shift g '()))))))
  (newline))
 
-(write-string "r0 should be ()\t\t")
-(sandbox
- (display (reset0 (cons 'a (reset0 (shift0 f (shift0 g '()))))))
- (newline))
+;; (write-string "r0 should be ()\t\t")
+;; (sandbox
+;;  (display (reset0 (cons 'a (reset0 (shift0 f (shift0 g '()))))))
+;;  (newline))
 
-(write-string "r  should be (a)\t")
+(write-string "should be (a)\t\t")
 (sandbox
  (display (reset (let ((y (shift f (cons 'a (f '()))))) (shift g y))))
  (newline))
 
-(write-string "p  should be ()\t\t")
-(sandbox
- (display (prompt (let ((y (control f (cons 'a (f '()))))) (control g y))))
- (newline))
-
-; Shan sez this is an infinite loop... Kiselyov turns this into a printing
-; loop by adding (display) somewhere, have to see if I can replicate that.
-; I dunno if the name has to be 'f' in both control parts
-
-;(prompt (begin (control f (begin (f 0) (f 0)))
-;	       (control f (begin (f 0) (f 0)))))
+;; (write-string "p  should be ()\t\t")
+;; (sandbox
+;;  (display (prompt (let ((y (control f (cons 'a (f '()))))) (control g y))))
+;;  (newline))
 
 ;;;(write-string "should be 132342344234442344442344444234444442344...\n\t  ")
 ;;; with reset2 it /is/ an infinite loop, just not the desired one...
@@ -229,28 +227,28 @@
 ;;;	      (control f (begin (f (display 3)) (f (display 4))))))
 ;;;(newline)
 
-(write-string "r  should be (a)\t")
+(write-string "should be (a)\t\t")
 (sandbox
  (display (reset (let ((y (shift f (cons 'a (f '()))))) (shift g y))))
  (newline))
 
-(write-string "r0 should be (a)\t")
-(sandbox
- (display (reset0 (let ((y (shift0 f (cons 'a (f '()))))) (shift0 g y))))
- (newline))
+;; (write-string "r0 should be (a)\t")
+;; (sandbox
+;;  (display (reset0 (let ((y (shift0 f (cons 'a (f '()))))) (shift0 g y))))
+;;  (newline))
 
-(write-string "p  should be ()\t\t")
-(sandbox
- (display (prompt (let ((y (control f (cons 'a (f '()))))) (control g y))))
- (newline))
+;; (write-string "p  should be ()\t\t")
+;; (sandbox
+;;  (display (prompt (let ((y (control f (cons 'a (f '()))))) (control g y))))
+;;  (newline))
 
-(write-string "p0 should be ()\t\t")
-(sandbox
- (display
-  (reset (prompt0 (let ((y (control0 f (cons 'a (f '()))))) (control0 g y)))))
- (newline))
+;; (write-string "p0 should be ()\t\t")
+;; (sandbox
+;;  (display
+;;   (reset (prompt0 (let ((y (control0 f (cons 'a (f '()))))) (control0 g y)))))
+;;  (newline))
 
-(write-string "r  should be (a b)\t")
+(write-string "should be (a b)\t\t")
 (sandbox
  (display
   (reset
@@ -259,41 +257,41 @@
 		      (shift h y)))))))
  (newline))
 
-(write-string "p  should be (a)\t")
-(sandbox
- (display
-  (prompt
-   (prompt (cons 'a (prompt
-		     (let ((y (control f (control g (cons 'b (f '()))))))
-		       (control h y)))))))
- (newline))
+;; (write-string "p  should be (a)\t")
+;; (sandbox
+;;  (display
+;;   (prompt
+;;    (prompt (cons 'a (prompt
+;; 		     (let ((y (control f (control g (cons 'b (f '()))))))
+;; 		       (control h y)))))))
+;;  (newline))
 
-(write-string "r0 should be (b)\t")
-(sandbox
- (display
-  (reset0
-   (reset0 (cons 'a (reset0
-		     (let ((y (shift0 f (shift0 g (cons 'b (f '()))))))
-		       (shift0 h y)))))))
- (newline))
+;; (write-string "r0 should be (b)\t")
+;; (sandbox
+;;  (display
+;;   (reset0
+;;    (reset0 (cons 'a (reset0
+;; 		     (let ((y (shift0 f (shift0 g (cons 'b (f '()))))))
+;; 		       (shift0 h y)))))))
+;;  (newline))
 
 ; haskeem fails this -- UNKNOWN ISSUE! TODO: investigate!
 
-(write-string "p0 should be ()\t\t")
-(sandbox
- (display
-  (prompt0
-   (prompt0 (cons 'a (prompt0
-		      (let ((y (control0 f (control0 g (cons 'b (f '()))))))
-			(control0 h y)))))))
- (newline))
+;; (write-string "p0 should be ()\t\t")
+;; (sandbox
+;;  (display
+;;   (prompt0
+;;    (prompt0 (cons 'a (prompt0
+;; 		      (let ((y (control0 f (control0 g (cons 'b (f '()))))))
+;; 			(control0 h y)))))))
+;;  (newline))
 
 (write-string "two-armed tests\n")
 (write-string "test 1: non-trivial shift only in false arm of if\n")
 (define (doit1 flag)
   (if flag
-      (write-string "r  should be (1 3)\t")
-      (write-string "r  should be (1 4 2 5)\t"))
+      (write-string "should be (1 3)\t\t")
+      (write-string "should be (1 4 2 5)\t"))
   (sandbox
    (display
     (cons 1 (reset (cons 2 (if flag
@@ -307,8 +305,8 @@
 (write-string "test 2: reverse of previous\n")
 (define (doit2 flag)
   (if flag
-      (write-string "r  should be (1 4 2 5)\t")
-      (write-string "r  should be (1 3)\t"))
+      (write-string "should be (1 4 2 5)\t")
+      (write-string "should be (1 3)\t\t"))
   (sandbox
    (display
     (cons 1 (reset (cons 2 (if flag
@@ -322,7 +320,7 @@
 (write-string "test 3: wrong? expansion of test 1\n")
 
 (define (doit3 flag)
-  (write-string "r  should be (1 4 3)\t")	; independent of flag
+  (write-string "should be (1 4 3)\t")	; independent of flag
   (sandbox
    (display
     (cons 1
@@ -339,8 +337,8 @@
 (write-string "test 4: expansion of test 2\n")
 (define (doit4 flag)
   (if flag
-      (write-string "r  should be (1 4 2 3)\t")
-      (write-string "r  should be (1 4 2 5)\t"))
+      (write-string "should be (1 4 2 3)\t")
+      (write-string "should be (1 4 2 5)\t"))
   (sandbox
    (display
     (cons 1
@@ -355,8 +353,8 @@
 (write-string "test 5: modified version, with (shift) in both arms of (if)\n")
 (define (doit5 flag)
   (if flag
-      (write-string "r  should be (1 3 2 4)\t")
-      (write-string "r  should be (1 5 2 6)\t"))
+      (write-string "should be (1 3 2 4)\t")
+      (write-string "should be (1 5 2 6)\t"))
   (sandbox
    (display
     (cons 1
@@ -373,8 +371,8 @@
 
 (define (doit6 flag)
   (if flag
-      (write-string "r  should be (1 3 2 4)\t")
-      (write-string "r  should be (1 5 2 6)\t"))
+      (write-string "should be (1 3 2 4)\t")
+      (write-string "should be (1 5 2 6)\t"))
   (sandbox
    (display
     (cons 1
@@ -388,89 +386,84 @@
 
 (write-string "examples from Queinnec, augmented to test all versions\n")
 
-(write-string "prompt/control examples\n")
-(write-string "should be 3\t\t")
-(sandbox
- (display (prompt (* 2 (control f 3))))
- (newline))
-
-(write-string "should be 30\t\t")
-(sandbox
- (display (prompt (* 2 (control f (* 5 (f 3))))))
- (newline))
-
-(write-string "should be 12\t\t")
-(sandbox
- (display (prompt (* 2 (control f (f (f 3))))))
- (newline))
-
-(write-string "should be 6\t\t")
-(sandbox
- (display ((prompt (* 2 (control f f))) 3))
- (newline))
-
-(write-string "should be 35\t\t")
-(sandbox
- (display (prompt (* 5
-		     (prompt (* 2
-				(control f2 (* 3 (control f3 7))))))))
- (newline))
-
-; haskeem quasi-fails this: because it's a (lambda () ...), it escapes,
-; and so at the end there's an uncaught exception which however carries
-; along the correct value as its payload. So I think haskeem would handle
-; this correctly if there were an implicit top-level catcher
-
-(write-string "should be 7\t\t")
-(sandbox
- (display (prompt (* 5 (
-			(prompt (* 2
-				   (control f2 (lambda ()
-						 (* 3 (control f3 7))))))))))
- (newline))
-
-(write-string "should be 21\t\t")
-(sandbox
- (display (prompt (* 5
-		     ((lambda (x) (control f1 x))
-		      (* 3 (control f2 (* 2 (f2 7))))))))
- (newline))
-
-(write-string "prompt0/control0 examples\n")
-(write-string "should be 3\t\t")
-(sandbox
- (display (prompt0 (* 2 (control0 f 3))))
- (newline))
-
-(write-string "should be 30\t\t")
-(sandbox
- (display (prompt0 (* 2 (control0 f (* 5 (f 3))))))
- (newline))
-
-(write-string "should be 12\t\t")
-(sandbox
- (display (prompt0 (* 2 (control0 f (f (f 3))))))
- (newline))
-
-(write-string "should be 6\t\t")
-(sandbox
- (display ((prompt0 (* 2 (control0 f f))) 3))
- (newline))
+(write-string "prompt/control examples (withdrawn for now)\n")
+;; (write-string "should be 3\t\t")
+;; (sandbox
+;;  (display (prompt (* 2 (control f 3))))
+;;  (newline))
+;; 
+;; (write-string "should be 30\t\t")
+;; (sandbox
+;;  (display (prompt (* 2 (control f (* 5 (f 3))))))
+;;  (newline))
+;; 
+;; (write-string "should be 12\t\t")
+;; (sandbox
+;;  (display (prompt (* 2 (control f (f (f 3))))))
+;;  (newline))
+;; 
+;; (write-string "should be 6\t\t")
+;; (sandbox
+;;  (display ((prompt (* 2 (control f f))) 3))
+;;  (newline))
+;; 
+;; (write-string "should be 35\t\t")
+;; (sandbox
+;;  (display (prompt (* 5
+;; 		     (prompt (* 2
+;; 				(control f2 (* 3 (control f3 7))))))))
+;;  (newline))
 
-(write-string "should be 7\t\t")
-(sandbox
- (display (prompt0 (* 5
-		      (prompt0 (* 2
-				  (control0 f2 (* 3 (control0 f3 7))))))))
- (newline))
+;; (write-string "should be 7\t\t")
+;; (sandbox
+;;  (display (prompt (* 5 (
+;; 			(prompt (* 2
+;; 				   (control f2 (lambda ()
+;; 						 (* 3 (control f3 7))))))))))
+;;  (newline))
+;; 
+;; (write-string "should be 21\t\t")
+;; (sandbox
+;;  (display (prompt (* 5
+;; 		     ((lambda (x) (control f1 x))
+;; 		      (* 3 (control f2 (* 2 (f2 7))))))))
+;;  (newline))
 
-(write-string "should be 7\t\t")
-(sandbox
- (display (prompt0 (* 5 (
-			(prompt0 (* 2
-				   (control0 f2 (lambda ()
-						 (* 3 (control0 f3 7))))))))))
- (newline))
+(write-string "prompt0/control0 examples (withdrawn for now)\n")
+;; (write-string "should be 3\t\t")
+;; (sandbox
+;;  (display (prompt0 (* 2 (control0 f 3))))
+;;  (newline))
+;; 
+;; (write-string "should be 30\t\t")
+;; (sandbox
+;;  (display (prompt0 (* 2 (control0 f (* 5 (f 3))))))
+;;  (newline))
+;; 
+;; (write-string "should be 12\t\t")
+;; (sandbox
+;;  (display (prompt0 (* 2 (control0 f (f (f 3))))))
+;;  (newline))
+;; 
+;; (write-string "should be 6\t\t")
+;; (sandbox
+;;  (display ((prompt0 (* 2 (control0 f f))) 3))
+;;  (newline))
+;; 
+;; (write-string "should be 7\t\t")
+;; (sandbox
+;;  (display (prompt0 (* 5
+;; 		      (prompt0 (* 2
+;; 				  (control0 f2 (* 3 (control0 f3 7))))))))
+;;  (newline))
+;; 
+;; (write-string "should be 7\t\t")
+;; (sandbox
+;;  (display (prompt0 (* 5 (
+;; 			(prompt0 (* 2
+;; 				   (control0 f2 (lambda ()
+;; 						 (* 3 (control0 f3 7))))))))))
+;;  (newline))
 
 ; There's something odd with this test: in mzscheme, it prints the
 ; result 21, then the whole rest of the test vanishes; apparently
@@ -478,12 +471,12 @@
 ; world just vanishes. If I surround this with a (reset ...), the
 ; test continues, but this doesn't print anything. Hmmm!
 
-(write-string "should be 21\t\t")
-(sandbox
- (display (prompt0 (* 5
-		      ((lambda (x) (control0 f1 x))
-		       (* 3 (control0 f2 (* 2 (f2 7))))))))
- (newline))
+;; (write-string "should be 21\t\t")
+;; (sandbox
+;;  (display (prompt0 (* 5
+;; 		      ((lambda (x) (control0 f1 x))
+;; 		       (* 3 (control0 f2 (* 2 (f2 7))))))))
+;;  (newline))
 
 (write-string "reset/shift examples\n")
 (write-string "should be 3\t\t")
@@ -528,50 +521,50 @@
 		     (* 3 (shift f2 (* 2 (f2 7))))))))
  (newline))
 
-(write-string "reset0/shift0 examples\n")
-(write-string "should be 3\t\t")
-(sandbox
- (display (reset0 (* 2 (shift0 f 3))))
- (newline))
-
-(write-string "should be 30\t\t")
-(sandbox
- (display (reset0 (* 2 (shift0 f (* 5 (f 3))))))
- (newline))
-
-(write-string "should be 12\t\t")
-(sandbox
- (display (reset0 (* 2 (shift0 f (f (f 3))))))
- (newline))
-
-(write-string "should be 6\t\t")
-(sandbox
- (display ((reset0 (* 2 (shift0 f f))) 3))
- (newline))
-
-(write-string "should be 7\t\t")
-(sandbox
- (display (reset0 (* 5
-		     (reset0 (* 2
-				(shift0 f2 (* 3 (shift0 f3 7))))))))
- (newline))
-
-(write-string "should be 7\t\t")
-(sandbox
- (display (reset0 (* 5 (
-		       (reset0 (* 2
-				 (shift0 f2 (lambda ()
-					     (* 3 (shift0 f3 7))))))))))
- (newline))
-
-(write-string "should be 42\t\t")
-(sandbox
- (display (reset0 (* 5
-		     ((lambda (x) (shift0 f1 x))
-		      (* 3 (shift0 f2 (* 2 (f2 7))))))))
- (newline))
+(write-string "reset0/shift0 examples (withdrawn for now)\n")
+;; (write-string "should be 3\t\t")
+;; (sandbox
+;;  (display (reset0 (* 2 (shift0 f 3))))
+;;  (newline))
+;; 
+;; (write-string "should be 30\t\t")
+;; (sandbox
+;;  (display (reset0 (* 2 (shift0 f (* 5 (f 3))))))
+;;  (newline))
+;; 
+;; (write-string "should be 12\t\t")
+;; (sandbox
+;;  (display (reset0 (* 2 (shift0 f (f (f 3))))))
+;;  (newline))
+;; 
+;; (write-string "should be 6\t\t")
+;; (sandbox
+;;  (display ((reset0 (* 2 (shift0 f f))) 3))
+;;  (newline))
+;; 
+;; (write-string "should be 7\t\t")
+;; (sandbox
+;;  (display (reset0 (* 5
+;; 		     (reset0 (* 2
+;; 				(shift0 f2 (* 3 (shift0 f3 7))))))))
+;;  (newline))
+;; 
+;; (write-string "should be 7\t\t")
+;; (sandbox
+;;  (display (reset0 (* 5 (
+;; 		       (reset0 (* 2
+;; 				 (shift0 f2 (lambda ()
+;; 					     (* 3 (shift0 f3 7))))))))))
+;;  (newline))
+;; 
+;; (write-string "should be 42\t\t")
+;; (sandbox
+;;  (display (reset0 (* 5
+;; 		     ((lambda (x) (shift0 f1 x))
+;; 		      (* 3 (shift0 f2 (* 2 (f2 7))))))))
+;;  (newline))
 
-(write-string "r  something actually useful! a small table of factorials\n")
+(write-string "something actually useful! a small table of factorials\n")
 
 ; Eventually we want to be able to use code like this:
 
@@ -635,8 +628,8 @@
 (doit7 #t)	; (1 3 5 2 4) -- mzscheme sez (1 3 2 4)
 
 (write-string
- "syntax error coming up! should be an error... this'll kill mzscheme\n")
+ "syntax error coming up! should be an error... this'll kill mzscheme,\n")
+(write-string
+ "but haskeem should catch the exception raised by the syntax error\n")
 
 (sandbox (display (+ 1 (reset (+ 2 (shift (+ k 1) 3))))))
-(write-string
- "haskeem should have caught the exception raised by the syntax error\n")
diff --git a/haskeem.cabal b/haskeem.cabal
--- a/haskeem.cabal
+++ b/haskeem.cabal
@@ -1,5 +1,5 @@
 Name:             haskeem
-Version:          0.7.12
+Version:          0.7.16
 Homepage:         http://www.korgwal.com/haskeem/
 Author:           Uwe Hollerbach <uh@alumni.caltech.edu>
 Maintainer:       Uwe Hollerbach <uh@alumni.caltech.edu>
diff --git a/haskeem.hs b/haskeem.hs
--- a/haskeem.hs
+++ b/haskeem.hs
@@ -18,7 +18,7 @@
 along with haskeem; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
-$Id: haskeem.hs,v 1.43 2009-08-08 05:09:00 uwe Exp $ -}
+$Id: haskeem.hs,v 1.49 2010-01-05 05:43:27 uwe Exp $ -}
 
 module Main where
 import Prelude
@@ -42,7 +42,7 @@
 -- haskeem version
 
 version :: String
-version = "0.7.12"
+version = "0.7.16"
 
 -- a variable under which any command-line arguments to a script are
 -- made available; empty for interactive mode
@@ -61,8 +61,9 @@
 
 evalAndPrint :: Env -> Bool -> String -> InputT IO ()
 evalAndPrint env pflag expr =
-  do ret <- liftIO (runErrorT (liftThrows (readExpr (dropWhile isSpace expr))
-              >>= evalPP env >>= evalLisp env [] 0))
+  do let eenv = EEnv env [] [] 0
+     ret <- liftIO (runErrorT (liftThrows (readExpr (dropWhile isSpace expr))
+              >>= evalPP eenv >>= evalLisp eenv))
      case ret of
           Left err -> outputStrLn (show err)
           Right val -> if pflag then outputStrLn (show val) else outputStr ""
@@ -101,7 +102,7 @@
 -- the actual REPL, combined with tasty haskeline goodness
 
 catcher :: CE.Exception -> InputT IO ()
-catcher e = outputStrLn "Interrupt!"
+catcher _ = outputStrLn "Interrupt!"
 
 doREPL :: Env -> InputT IO ()
 doREPL env =
@@ -132,7 +133,7 @@
   do env <- setupBindings (map String (drop 1 args)) False
      runInputT defaultSettings
                (runInit env >>
-                evalAndPrint env False ("(load \"" ++ (args !! 0) ++ "\")"))
+                evalAndPrint env False ("(load \"" ++ head args ++ "\")"))
 
 main :: IO ()
 main =
diff --git a/haskeem_readline.hs b/haskeem_readline.hs
--- a/haskeem_readline.hs
+++ b/haskeem_readline.hs
@@ -42,7 +42,7 @@
 -- haskeem version
 
 version :: String
-version = "0.7.12"
+version = "0.7.16"
 
 -- a variable under which any command-line arguments to a script are
 -- made available; empty for interactive mode
@@ -61,11 +61,12 @@
 
 evalAndPrint :: Env -> Bool -> String -> IO ()
 evalAndPrint env pflag expr =
-  do ret <- runErrorT (liftThrows (readExpr (dropWhile isSpace expr))
-              >>= evalPP env >>= evalLisp env [] 0)
+  do let eenv = EEnv env [] [] 0
+     ret <- runErrorT (liftThrows (readExpr (dropWhile isSpace expr))
+              >>= evalPP eenv >>= evalLisp eenv)
      case ret of
           Left err -> hPutStrLn stderr (show err)
-          Right val -> if pflag then putStrLn (show val) else putStr ""
+          Right val -> if pflag then print val else putStr ""
 
 -- if the environment variable HASKEEM_INIT is set, try to load that file
 
@@ -102,7 +103,7 @@
 readline prompt =
   do putStr prompt
      hFlush stdout
-     ret <- CE.try (getLine)
+     ret <- CE.try getLine
      case ret of
           Left err -> do hPutStrLn stderr "g'bye!"
                          exitWith (ExitFailure 1)
@@ -116,7 +117,7 @@
 data MyInterrupt = MyInt deriving Typeable
 
 catcher :: MyInterrupt -> IO ()
-catcher e = hPutStrLn stderr "Interrupt!"
+catcher _ = hPutStrLn stderr "Interrupt!"
 
 doREPL :: Env -> IO ()
 doREPL env =
@@ -128,7 +129,7 @@
                           then doREPL env
                           else do addHistory line
                                   catchDyn (evalAndPrint env True line)
-                                           (\e -> catcher e)
+                                           catcher
                                   doREPL env
   where isBlank [] = True
         isBlank _ = False
@@ -153,7 +154,7 @@
 runOne args =
   do env <- setupBindings (map String (drop 1 args)) False
      runInit env
-     evalAndPrint env False ("(load \"" ++ (args !! 0) ++ "\")")
+     evalAndPrint env False ("(load \"" ++ head args ++ "\")")
 
 main =
   do args <- getArgs
diff --git a/selftest.scm b/selftest.scm
--- a/selftest.scm
+++ b/selftest.scm
@@ -15,7 +15,7 @@
 ; along with haskeem; if not, write to the Free Software
 ; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
-; $Id: selftest.scm,v 1.46 2009-07-19 02:36:21 uwe Exp $
+; $Id: selftest.scm,v 1.48 2010-01-18 05:15:29 uwe Exp $
 
 (define start (epochtime))
 
@@ -881,6 +881,24 @@
 (chk-run lst '(list-unref lst 100))
 (chk-run -24 '(last lst))
 
+(chk-run '((4 2 6) (1 3 4 2 7 5 5 4))
+	 '(span even? '(4 2 6 1 3 4 2 7 5 5 4)))
+(chk-run '((4 2 6 8) (3 4 2 7 5 5 4))
+	 '(span even? '(4 2 6 8 3 4 2 7 5 5 4)))
+(chk-run '((4) (1 2 6 8 3 4 2 7 5 5 4))
+	 '(span even? '(4 1 2 6 8 3 4 2 7 5 5 4)))
+(chk-run '(() (1 2 6 8 3 4 2 7 5 5 4))
+	 '(span even? '(1 2 6 8 3 4 2 7 5 5 4)))
+(chk-run '((2 4 6 8 4 6 2 10) ())
+	 '(span even? '(2 4 6 8 4 6 2 10)))
+(chk-run '(() ()) '(span even? '()))
+
+(chk-run '((#\M) (#\i) (#\s #\s) (#\i) (#\s #\s) (#\i) (#\p #\p) (#\i))
+	 '(list-group-by eqv? (string->char "Mississippi")))
+(chk-run '((4) (1) (2 6 8) (3) (4 2) (7 5 5) (4))
+	 '(list-group-by (lambda (a b) (eqv? (even? a) (even? b)))
+			 '(4 1 2 6 8 3 4 2 7 5 5 4)))
+
 (chk-run '(x y) '(append '(x) '(y)))
 (chk-run '(a b c d) '(append '(a) '(b c d)))
 (chk-run '(a (b) (c)) '(append '(a (b)) '((c))))
@@ -2407,7 +2425,8 @@
   (catch-exceptions (chk-query "test directory" '(get-current-directory)))
   (catch-exceptions (chk-run #t '(set-current-directory "..")))
   (catch-exceptions (chk-run #t '(remove-directory test-dir1)))
-  (run-command (string-join-by " " "/bin/rm -rf" test-dir1)))
+  (catch-exceptions
+   (run-command (string-join-by " " "/bin/rm -rf" test-dir1))))
 
 (if (directory-exists? test-dir1)
     (write-string "\nSkipping file and directory I/O tests,\n"
diff --git a/stdlib.scm b/stdlib.scm
--- a/stdlib.scm
+++ b/stdlib.scm
@@ -18,7 +18,7 @@
 ; along with haskeem; if not, write to the Free Software
 ; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
-; $Id: stdlib.scm,v 1.43 2009-08-06 05:05:15 uwe Exp $
+; $Id: stdlib.scm,v 1.44 2010-01-18 05:15:29 uwe Exp $
 
 ; The haskeem standard library
 
@@ -259,6 +259,30 @@
   (cond ((null? lst) #f)
 	((proc (car lst)) (car lst))
 	(else (find proc (cdr lst)))))
+
+; This returns a partition of the input list: the longest prefix of the
+; input list for which (pred val) returns #t, and the remainder of the list.
+
+(define (span pred lst)
+  (cond ((null? lst) (list () ()))
+	((pred (car lst))
+	 (let ((st (span pred (cdr lst))))
+	   (list (cons (car lst) (car st)) (cadr st))))
+	(else (list () lst))))
+
+; This turns a list into a list-of-lists, where each sub-list is a group
+; of elements which compare equal according to the comparison function:
+; for example
+;	(list-group-by eqv? (string->char "Mississippi"))
+; returns
+;	((#\M) (#\i) (#\s #\s) (#\i) (#\s #\s) (#\i) (#\p #\p) (#\i))
+; with equal characters grouped together.
+
+(define (list-group-by cmp lst)
+  (if (null? lst)
+      ()
+      (let ((st (span (curry cmp (car lst)) (cdr lst))))
+	(cons (cons (car lst) (car st)) (list-group-by cmp (cadr st))))))
 
 ; This is defined this way, rather than as (for-each proc . lsts), so
 ; that the machinery will check that there is at least one list argument:
