diff --git a/Jukebox/Clausify.hs b/Jukebox/Clausify.hs
deleted file mode 100644
--- a/Jukebox/Clausify.hs
+++ /dev/null
@@ -1,446 +0,0 @@
-{-# LANGUAGE TypeOperators, BangPatterns #-}
-module Jukebox.Clausify where
-
-import Jukebox.Form
-import qualified Jukebox.Form as Form
-import Jukebox.Name
-import Data.List( maximumBy, sortBy, partition )
-import Data.Ord
-import Control.Monad.Reader
-import Control.Monad.State.Strict
-import qualified Jukebox.Seq as S
-import Jukebox.Seq(Seq)
-import qualified Jukebox.NameMap as NameMap
-import Jukebox.NameMap(NameMap)
-import qualified Jukebox.Map as Map
-import qualified Data.HashSet as Set
-import qualified Data.ByteString.Char8 as BS
-import Jukebox.Utils
-import Jukebox.Options
-import Control.Applicative
-
-newtype ClausifyFlags = ClausifyFlags { splitting :: Bool } deriving Show
-
-clausifyFlags =
-  inGroup "Clausifier options" $
-  ClausifyFlags <$>
-    bool "split"
-      ["Split the conjecture into several sub-conjectures.",
-       "Default: (off)"]
-
-----------------------------------------------------------------------
--- clausify
-
-clausify :: ClausifyFlags -> Problem Form -> CNF
-clausify flags inps = close inps (run . clausifyInputs S.Nil S.Nil)
- where
-  clausifyInputs theory obligs [] =
-    do return (toObligs (S.toList theory) (S.toList obligs))
-  
-  clausifyInputs theory obligs (inp:inps) | kind inp == Axiom =
-    do cs <- clausForm (tag inp) (what inp)
-       clausifyInputs (theory `S.append` cs) obligs inps
-
-  clausifyInputs theory obligs (inp:inps) | kind inp `elem` [Conjecture, Question] =
-    do clausifyObligs theory obligs (tag inp) (split' (what inp)) inps
-
-  clausifyObligs theory obligs s [] inps =
-    do clausifyInputs theory obligs inps
-  
-  clausifyObligs theory obligs s (a:as) inps =
-    do cs <- clausForm s (nt a)
-       clausifyObligs theory (obligs `S.append` S.Unit cs) s as inps
-
-  split' a | splitting flags = if null split_a then [true] else split_a
-    where split_a = split a
-  split' a                   = [a]
-
-split :: Form -> [Form]
-split p =
-  case positive p of
-    ForAll (Bind xs p) ->
-      [ ForAll (Bind xs p') | p' <- split p ]
-    
-    And ps ->
-      concatMap split (S.toList ps)
-    
-    p `Equiv` q ->
-      split (nt p \/ q) ++ split (p \/ nt q)
-
-    Or ps ->
-      snd $
-      maximumBy first
-      [ (siz q, [ Or (S.fromList (q':qs)) | q' <- sq ])
-      | (q,qs) <- select (S.toList ps)
-      , let sq = split q
-      ]
-
-    _ ->
-      [p]
- where
-  select []     = []
-  select (x:xs) = (x,xs) : [ (y,x:ys) | (y,ys) <- select xs ]
-  
-  first (n,x) (m,y) = n `compare` m
-  
-  siz (And ps)            = S.length ps
-  siz (ForAll (Bind _ p)) = siz p
-  siz (_ `Equiv` _)       = 2
-  siz _                   = 0
-
-{-  
-    Or ps | S.size ps > 0 && n > 0 ->
-      [ Or (S.fromList (p':ps')) | p' <- split p ]
-     where
-      pns = [(p,siz p) | p <- S.toList ps]
-      ((p,n),pns') = getMax (head pns) [] (tail pns)
-      ps' = [ p' | (p',_) <- pns' ]
-    
-  getMax pn@(p,n) pns [] = (pn,pns)
-  getMax pn@(p,n) pns (qm@(q,m):qms)
-    | m > n     = getMax qm (pn:pns) qms
-    | otherwise = getMax pn (qm:pns) qms
--}
-
-----------------------------------------------------------------------
--- core clausification algorithm
-
-clausForm :: BS.ByteString -> Form -> M [Input Clause]
-clausForm s p =
-  withName s $
-    do miniscoped      <- miniscope . check . simplify                      . check $ p
-       noEquivPs       <- removeEquiv                                       . check $ miniscoped
-       noExistsPs      <- mapM removeExists                                 . check $ noEquivPs
-       noExpensiveOrPs <- fmap concat . mapM removeExpensiveOr              . check $ noExistsPs
-       noForAllPs      <- lift . lift . mapM uniqueNames                    . check $ noExpensiveOrPs
-       let !cnf_        = S.concatMap cnf                                   . check $ noForAllPs
-           !simp        = simplifyCNF . fmap S.toList                       . check $ cnf_
-           cs           = S.toList . fmap clause                                    $ simp
-           inps         = [ Input (BS.append s (BS.pack i)) Axiom c
-                          | (c, i) <- zip cs ("":
-                                        [ '_':show i | i <- [1..] ]) ]
-       return $! force . check                                                      $ inps
-
-----------------------------------------------------------------------
--- miniscoping
-miniscope :: Form -> M Form
-miniscope t@Literal{} = return t
-miniscope (Not f) = fmap Not (miniscope f)
-miniscope (And fs) = fmap And (S.mapM miniscope fs)
-miniscope (Or fs) = fmap Or (S.mapM miniscope fs)
-miniscope (Equiv f g) = liftM2 Equiv (miniscope f) (miniscope g)
-miniscope (ForAll (Bind xs f)) = miniscope f >>= forAll xs
-miniscope (Exists (Bind xs f)) = miniscope f >>= forAll xs . nt >>= return . nt
-
-forAll :: NameMap Variable -> Form -> M Form
-forAll xs a | Map.null xs = return a
-forAll xs a =
-  case positive a of
-    And as ->
-      fmap And (S.mapM (forAll xs) as)
-    
-    ForAll (Bind ys a)
-      | Map.null m -> return (ForAll (Bind ys a))
-      | otherwise -> fmap (forAll' ys) (forAll m a)
-      where m = xs Map.\\ ys
-            forAll' vs (ForAll (Bind vs' t)) = ForAll (Bind (vs `Map.union` vs') t)
-            forAll' vs t = ForAll (Bind vs t)
-
-    Or as -> forAllOr xs [ (a, free a) | a <- S.toList as ]
-
-    _ -> return (ForAll (Bind xs a))
-
-forAllOr :: NameMap Variable -> [(Form, NameMap Variable)] -> M Form
-forAllOr xs avss = do { y <- yes; forAll xs' (y \/ no) }
-  where
-    v         = head (NameMap.toList xs)
-    xs'       = NameMap.delete v xs
-    (bs1,bs2) = partition ((v `NameMap.member`) . snd) avss
-    no        = orl [ b | (b,_) <- bs2 ]
-    body      = orl [ b | (b,_) <- bs1 ]
-    yes       = case bs1 of
-                  []      -> return (orl [])
-                  [(b,_)] -> forAll (NameMap.singleton v) b
-                  _       -> return (ForAll (Bind (NameMap.singleton v) body))
-    orl       = foldr (\/) false
-
-----------------------------------------------------------------------
--- removing equivalences
-
--- removeEquiv p -> ps :
---   POST: And ps is equivalent to p (modulo extra symbols)
---   POST: ps has no Equiv and no Not
-removeEquiv :: Form -> M [Form]
-removeEquiv p =
-  do (defs,pos,_) <- removeEquivAux False p
-     return (S.toList (defs `S.append` S.Unit pos))
-
--- removeEquivAux inEquiv p -> (defs,pos,neg) :
---   PRE: inEquiv is True when we are "under" an Equiv
---   POST: defs is a list of definitions, under which
---         pos is equivalent to p and neg is equivalent to nt p
--- (the reason why "neg" and "nt pos" can be different, is
--- because we want to always code an equivalence as
--- a conjunction of two disjunctions, which leads to fewer
--- clauses -- the "neg" part of the result for the case Equiv
--- below makes use of this)
-removeEquivAux :: Bool -> Form -> M (Seq Form,Form,Form)
-removeEquivAux inEquiv p =
-  case simple p of
-    Not p ->
-      do (defs,pos,neg) <- removeEquivAux inEquiv p
-         return (defs,neg,pos)
-  
-    And ps ->
-      do dps <- sequence [ removeEquivAux inEquiv p | p <- S.toList ps ]
-         let (defss,poss,negs) = unzip3 dps
-         return ( S.concat defss
-                , And (S.fromList poss)
-                , Or  (S.fromList negs)
-                )
-
-    ForAll (Bind xs p) ->
-      do (defs,pos,neg) <- removeEquivAux inEquiv p
-         return ( defs
-                , ForAll (Bind xs pos)
-                , Exists (Bind xs neg)
-                )
-
-    p `Equiv` q ->
-      do (defsp,posp,negp)    <- removeEquivAux True p
-         (defsq,posq,negq)    <- removeEquivAux True q
-         (defsp',posp',negp') <- makeCopyable inEquiv posp negp
-         (defsq',posq',negq') <- makeCopyable inEquiv posq negq
-         return ( S.concat [defsp, defsq, defsp', defsq']
-                , (negp' \/ posq') /\ (posp' \/ negq')
-                , (negp' \/ negq') /\ (posp' \/ posq')
-                )
-
-    Literal l ->
-      do return (S.Nil,Literal l,Literal (neg l))
-
--- makeCopyable turns an argument to an Equiv into something that we are
--- willing to copy. There are two such cases: (1) when the Equiv is
--- not under another Equiv (because we have to copy arguments to an Equiv
--- at least once anyway), (2) if the formula is small.
--- All other formulas will be made small (by means of a definition)
--- before we copy them.
-makeCopyable :: Bool -> Form -> Form -> M (Seq Form,Form,Form)
-makeCopyable inEquiv pos neg
-  | isSmall pos || not inEquiv =
-    -- we skolemize here so that we reuse the skolem function
-    -- (if we do this after copying, we get several skolemfunctions)
-    do pos' <- removeExists pos
-       neg' <- removeExists neg
-       return (S.Nil,pos',neg')
-
-  | otherwise =
-    do dp <- literal "equiv" (free pos)
-       return (S.fromList [Literal (Neg dp) \/ pos, Literal (Pos dp) \/ neg], Literal (Pos dp), Literal (Neg dp))
- where
-  -- a formula is small if it is already a literal
-  isSmall (Literal _)         = True
-  isSmall (Not p)             = isSmall p
-  isSmall (ForAll (Bind _ p)) = isSmall p
-  isSmall (Exists (Bind _ p)) = isSmall p
-  isSmall _                   = False
-
-----------------------------------------------------------------------
--- skolemization
-
--- removeExists p -> p'
---   PRE: p has no Equiv and no Not
---   POST: p' is equivalent to p (modulo extra symbols)
---   POST: p' has no Equiv, no Exists, and no Not
-removeExists :: Form -> M Form
-removeExists (And ps) =
-  do ps <- sequence [ removeExists p | p <- S.toList ps ]
-     return (And (S.fromList ps))
-
-removeExists (Or ps) =
-  do ps <- sequence [ removeExists p | p <- S.toList ps ]
-     return (Or (S.fromList ps))
-    
-removeExists (ForAll (Bind xs p)) =
-  do p' <- removeExists p
-     return (ForAll (Bind xs p'))
-    
-removeExists t@(Exists (Bind xs p)) =
-  -- skolemterms have only variables as arguments, arities are large(r)
-  do ss <- sequence [ fmap (x |=>) (skolem x (free t)) | x <- NameMap.toList xs ]
-     removeExists (subst (foldr (|+|) ids ss) p)
-  {-
-  -- skolemterms can have other skolemterms as arguments, arities are small(er)
-  -- disadvantage: skolemterms are very complicated and deep
-  do p' <- skolemize p
-     t <- skolem x (S.delete x (free p'))
-     return (subst (x |=> t) p')
-  -}
-
-removeExists lit =
-  do return lit
-
--- TODO: Avoid recomputing "free" at every step, by having
--- skolemize return the set of free variables as well
-
--- TODO: Investigate skolemizing top-down instead, find the right
--- optimization
-
-----------------------------------------------------------------------
--- make cheap Ors
-
-removeExpensiveOr :: Form -> M [Form]
-removeExpensiveOr p =
-  do (defs,p',_) <- removeExpensiveOrAux p
-     return (S.toList (defs `S.append` S.Unit p'))
-
--- cost: represents how it expensive it is to clausify a formula
-type Cost = (Integer,Integer) -- (#clauses, #literals)
-
-unitCost :: Cost
-unitCost = (1,1)
-
-andCost :: [Cost] -> Cost
-andCost cs = (sum (map fst cs), sum (map snd cs))
-
-orCost :: [Cost] -> Cost
-orCost []           = (1,0)
-orCost [c]          = c
-orCost ((c1,l1):cs) = (c1 * c2, c1 * l2 + c2 * l1)
- where
-  (c2,l2) = orCost cs
-  
-removeExpensiveOrAux :: Form -> M (Seq Form,Form,Cost)
-removeExpensiveOrAux (And ps) =
-  do dcs <- sequence [ removeExpensiveOrAux p | p <- S.toList ps ]
-     let (defss,ps,costs) = unzip3 dcs
-     return (S.concat defss, And (S.fromList ps), andCost costs)
-
-removeExpensiveOrAux (Or ps) =
-  do dcs <- sequence [ removeExpensiveOrAux p | p <- S.toList ps ]
-     let (defss,ps,costs) = unzip3 dcs
-     (defs2,p,c) <- makeOr (sortBy (comparing snd) (zip ps costs))
-     return (S.concat defss `S.append` defs2,p,c)
-
-removeExpensiveOrAux (ForAll (Bind xs p)) =
-  do (defs,p',cost) <- removeExpensiveOrAux p
-     return (fmap (ForAll . Bind xs) defs, ForAll (Bind xs p'), cost)
-
-removeExpensiveOrAux lit =
-  do return (S.Nil, lit, unitCost)
-
--- input is sorted; small costs first
-makeOr :: [(Form,Cost)] -> M (Seq Form,Form,Cost)
-makeOr [] =
-  do return (S.Nil, false, orCost [])
-
-makeOr [(f,c)] =
-  do return (S.Nil,f,c)
-
-makeOr fcs
-  | null fcs2 =
-    do return (S.Nil, Or (S.fromList (map fst fcs1)), orCost (map snd fcs1))
-
-  | otherwise =
-    do d <- literal "or" (free (map fst fcs2))
-       (defs,p,_) <- makeOr ((Literal (Neg d),unitCost):fcs2)
-       return ( defs `S.snoc` p
-              , Or (S.fromList (Literal (Pos d) : map fst fcs1))
-              , orCost (unitCost : map snd fcs1)
-              )
- where
-  (fcs1,fcs2) = split [] fcs
-  
-  split fcs1 []                            = (fcs1,[])
-  split fcs1 (fc@(_,(cc,_)):fcs) | cc <= 1 = split (fc:fcs1) fcs
-  split fcs1 fcs@((_,(cc,_)):_)  | cc <= 2 = (take 2 fcs ++ fcs1, drop 2 fcs)
-  split fcs1 fcs                           = (take 1 fcs ++ fcs1, drop 1 fcs)
-
-----------------------------------------------------------------------
--- clausification
-
--- cnf p = cs
---   PRE: p has no Equiv, no Exists, and no Not,
---        and each variable is only bound once
---   POST: And (map Or cs) is equivalent to p
-cnf :: Form -> Seq (Seq Literal)
-cnf (ForAll (Bind _ p)) = cnf p
-cnf (And ps)            = S.concatMap cnf ps
-cnf (Or ps)             = cross (fmap cnf ps)
-cnf (Literal x)         = S.Unit (S.Unit x)
-
-cross :: Seq (Seq (Seq Literal)) -> Seq (Seq Literal)
-cross S.Nil = S.Unit S.Nil
-cross (S.Unit x) = x
-cross (S.Append cs1 cs2) = liftM2 S.append (cross cs1) (cross cs2)
-
-----------------------------------------------------------------------
--- simplification of CNF
-
-simplifyCNF :: Seq [Literal] -> [[Literal]]
-simplifyCNF =
-  -- nub: don't generate multiple copies of identical clauses
-  nub . S.concatMap (tautElim . unify [])
-  where -- remove negative variable equalities X != Y by substitution
-        unify xs [] = xs
-        unify xs (Neg (Var v :=: t@Var{}):ys) =
-          unify (subst (v |=> t) xs) (subst (v |=> t) ys)
-        unify xs (l:ys) = unify (l:xs) ys
-        -- simplify p | ~p or t = t to true.
-        tautElim ls
-          | Set.null (pos `Set.intersection` neg) && not (any tauto ls)
-            -- reorder the order of the literals in the clause
-            -- so that more clauses become equal;
-            -- also, remove duplicate literals from the clause
-            = S.Unit (map Neg (Set.toList neg) ++ map Pos (Set.toList pos))
-          | otherwise = S.Nil
-          where pos = Set.fromList [ l | Pos l <- ls ]
-                neg = Set.fromList [ l | Neg l <- ls ]
-                tauto (Pos (t :=: u)) = t == u
-                tauto _ = False
-
-----------------------------------------------------------------------
--- monad
-
-type M = ReaderT Tag (StateT Int NameM)
-
-run :: M a -> NameM a
-run x = evalStateT (runReaderT x BS.empty) 0
-
-skolemName :: Named a => String -> a -> M Name
-skolemName prefix v = do
-  i <- get
-  put (i+1)
-  s <- getName
-  lift . lift . newName $ prefix ++ show i ++ concat [ "_" ++ t | t <- map BS.unpack [s, baseName v], not (null t) ]
-
-nextSk :: M Int
-nextSk = do
-  i <- get
-  put (i+1)
-  return i
-
-withName :: Tag -> M a -> M a
-withName s m = lift (runReaderT m s)
-
-getName :: M Tag
-getName = ask
-
-skolem :: Variable -> NameMap Variable -> M Term
-skolem (v ::: t) vs =
-  do n <- skolemName "sK" v
-     let f = n ::: FunType (map typ args) t
-     return (f :@: map Var args)
- where
-  args = NameMap.toList vs
-
-literal :: String -> NameMap Variable -> M Atomic
-literal w vs =
-  do n <- skolemName "sP" w
-     let p = n ::: FunType (map typ args) O
-     return (Tru (p :@: map Var args))
- where
-  args = NameMap.toList vs
-
-----------------------------------------------------------------------
--- the end.
diff --git a/Jukebox/Form.hs b/Jukebox/Form.hs
deleted file mode 100644
--- a/Jukebox/Form.hs
+++ /dev/null
@@ -1,716 +0,0 @@
--- Formulae, inputs, terms and so on.
---
--- "Show" instances for several of these types are found in TPTP.Print.
-
-{-# LANGUAGE DeriveDataTypeable, FlexibleContexts, Rank2Types, GADTs, TypeOperators, ScopedTypeVariables, BangPatterns, PatternGuards #-}
-module Jukebox.Form where
-
-import Prelude hiding (sequence, mapM)
-import qualified Jukebox.Seq as S
-import Jukebox.Seq(Seq)
-import Data.Hashable
-import qualified Jukebox.Map as Map
-import Jukebox.NameMap(NameMap)
-import qualified Jukebox.NameMap as NameMap
-import Data.Ord
-import qualified Data.ByteString.Char8 as BS
-import Jukebox.Name
-import Control.Monad.State.Strict hiding (sequence, mapM)
-import Data.List hiding (nub)
-import Jukebox.Utils
-import Data.Typeable(Typeable)
-import Data.Monoid
-import Data.Traversable
-
--- Set to True to switch on some sanity checks
-debugging :: Bool
-debugging = False
-
-----------------------------------------------------------------------
--- Types
-
-data DomainSize = Finite Int | Infinite deriving (Eq, Ord, Show, Typeable)
-
-data Type =
-    O
-  | Type {
-      tname :: {-# UNPACK #-} !Name,
-      -- type is monotone when domain size is >= tmonotone
-      tmonotone :: DomainSize,
-      -- if there is a model of size >= tsize then there is a model of size tsize
-      tsize :: DomainSize } deriving Typeable
-
-data FunType = FunType { args :: [Type], res :: Type } deriving (Eq, Typeable)
-
--- Helper function for defining (Eq, Ord, Hashable) instances
-typeMaybeName :: Type -> Maybe Name
-typeMaybeName O = Nothing
-typeMaybeName Type{tname = t} = Just t
-
-instance Eq Type where
-  t1 == t2 = typeMaybeName t1 == typeMaybeName t2
-
-instance Ord Type where
-  compare = comparing typeMaybeName
-
-instance Hashable Type where
-  hashWithSalt s = hashWithSalt s . typeMaybeName
-
-instance Named Type where
-  name O = nameO
-  name Type{tname = t} = t
-
--- Typeclass of "things that have a type"
-class Typed a where
-  typ :: a -> Type
-
-instance Typed Type where
-  typ = id
-
-instance Typed FunType where
-  typ = res
-
-instance Typed b => Typed (a ::: b) where
-  typ (_ ::: t) = typ t
-
-----------------------------------------------------------------------
--- Terms
-
-type Variable = Name ::: Type
-type Function = Name ::: FunType
-data Term = Var Variable | Function :@: [Term] deriving (Eq, Ord)
-
-instance Hashable Term where
-  hashWithSalt s = hashWithSalt s . convert
-    where convert (Var x) = Left x
-          convert (f :@: ts) = Right (f, ts)
-
-instance Named Term where
-  name (Var x) = name x
-  name (f :@: _) = name f
-
-instance Typed Term where
-  typ (Var x) = typ x
-  typ (f :@: _) = typ f
-
-newSymbol :: Named a => a -> b -> NameM (Name ::: b)
-newSymbol x ty = fmap (::: ty) (newName x)
-
-newFunction :: Named a => a -> [Type] -> Type -> NameM Function
-newFunction x args res = newSymbol x (FunType args res)
-
-newType :: Named a => a -> NameM Type
-newType x = do
-  n <- newName x
-  return (Type n Infinite Infinite)
-
-funArgs :: Function -> [Type]
-funArgs (_ ::: ty) = args ty
-
-arity :: Function -> Int
-arity = length . funArgs
-
-size :: Term -> Int
-size Var{} = 1
-size (f :@: xs) = 1 + sum (map size xs)
-
-----------------------------------------------------------------------
--- Literals
-
-infix 8 :=:
-data Atomic = Term :=: Term | Tru Term
-
--- Helper for (Eq Atomic, Ord Atomic, Hashable Atomic) instances
-normAtomic :: Atomic -> Either (Term, Term) Term
-normAtomic (t1 :=: t2) | t1 > t2 = Left (t2, t1)
-                       | otherwise = Left (t1, t2)
-normAtomic (Tru p) = Right p
-
-instance Eq Atomic where
-  t1 == t2 = normAtomic t1 == normAtomic t2
-
-instance Ord Atomic where
-  compare = comparing normAtomic
-
-instance Hashable Atomic where
-  hashWithSalt s = hashWithSalt s . normAtomic
-
-data Signed a = Pos a | Neg a deriving (Show, Eq, Ord)
-
-instance Hashable a => Hashable (Signed a) where
-  hashWithSalt s = hashWithSalt s . convert
-    where convert (Pos x) = Left x
-          convert (Neg x) = Right x
-
-instance Functor Signed where
-  fmap f (Pos x) = Pos (f x)
-  fmap f (Neg x) = Neg (f x)
-type Literal = Signed Atomic
-
-neg :: Signed a -> Signed a
-neg (Pos x) = Neg x
-neg (Neg x) = Pos x
-
-the :: Signed a -> a
-the (Pos x) = x
-the (Neg x) = x
-
-pos :: Signed a -> Bool
-pos (Pos _) = True
-pos (Neg _) = False
-
-signForm :: Signed a -> Form -> Form
-signForm (Pos _) f = f
-signForm (Neg _) f = Not f
-
-----------------------------------------------------------------------
--- Formulae
-
--- Invariant: each name is bound only once on each path
--- i.e. nested quantification of the same variable twice is not allowed
--- Not OK: ![X]: (... ![X]: ...)
--- OK:     (![X]: ...) & (![X]: ...)
--- Free variables must also not be bound inside subformulae
-data Form
-  = Literal Literal
-  | Not Form
-  | And (Seq Form)
-  | Or (Seq Form)
-  | Equiv Form Form
-  | ForAll {-# UNPACK #-} !(Bind Form)
-  | Exists {-# UNPACK #-} !(Bind Form)
-    -- Just exists so that parsing followed by pretty-printing is
-    -- somewhat lossless; the simplify function will get rid of it
-  | Connective Connective Form Form
-
--- Miscellaneous connectives that exist in TPTP
-data Connective = Implies | Follows | Xor | Nor | Nand
-
-connective :: Connective -> Form -> Form -> Form
-connective Implies t u = nt t \/ u
-connective Follows t u = t \/ nt u
-connective Xor t u = nt (t `Equiv` u)
-connective Nor t u = nt (t \/ u)
-connective Nand t u = nt (t /\ u)
-
-data Bind a = Bind (NameMap Variable) a
-
-true, false :: Form
-true = And S.Nil
-false = Or S.Nil
-
-isTrue, isFalse :: Form -> Bool
-isTrue (And S.Nil) = True
-isTrue _ = False
-isFalse (Or S.Nil) = True
-isFalse _ = False
-
-nt :: Form -> Form
-nt (Not a) = a
-nt a       = Not a
-
-(.=>.) :: Form -> Form -> Form
-(.=>.) = connective Implies
-
-(.=.) :: Term -> Term -> Form
-t .=. u | typ t == O = Literal (Pos (Tru t)) `Equiv` Literal (Pos (Tru u))
-        | otherwise = Literal (Pos (t :=: u))
-
-(/\), (\/) :: Form -> Form -> Form
-And as /\ And bs = And (as `S.append` bs)
-a      /\ b | isFalse a || isFalse b = false
-And as /\ b      = And (b `S.cons` as)
-a      /\ And bs = And (a `S.cons` bs)
-a      /\ b      = And (S.Unit a `S.append` S.Unit b)
-
-Or as \/ Or bs = Or (as `S.append` bs)
-a     \/ b | isTrue a || isTrue b = true
-Or as \/ b     = Or (b `S.cons` as)
-a     \/ Or bs = Or (a `S.cons` bs)
-a     \/ b     = Or (S.Unit a `S.append` S.Unit b)
-
-closeForm :: Form -> Form
-closeForm f | Map.null vars = f
-            | otherwise = ForAll (Bind vars f)
-  where vars = free f
-
-conj, disj :: S.List f => f Form -> Form
-conj = And . S.fromList
-disj = Or . S.fromList
-
--- remove Not from the root of a problem
-positive :: Form -> Form
-positive (Not f) = notInwards f
--- Some connectives are fairly not-ish
-positive (Connective c t u)         = positive (connective c t u)
-positive f = f
-
-notInwards :: Form -> Form
-notInwards (And as)             = Or (fmap notInwards as)
-notInwards (Or as)              = And (fmap notInwards as)
-notInwards (a `Equiv` b)        = notInwards a `Equiv` b
-notInwards (Not a)              = positive a
-notInwards (ForAll (Bind vs a)) = Exists (Bind vs (notInwards a))
-notInwards (Exists (Bind vs a)) = ForAll (Bind vs (notInwards a))
-notInwards (Literal l)          = Literal (neg l)
-notInwards (Connective c t u)   = notInwards (connective c t u)
-
--- remove Exists and Or from the top level of a formula
-simple :: Form -> Form
-simple (Or as)              = Not (And (fmap nt as))
-simple (Exists (Bind vs a)) = Not (ForAll (Bind vs (nt a)))
-simple (Connective c t u)   = simple (connective c t u)
-simple a                    = a
-
--- perform some easy algebraic simplifications
-simplify t@Literal{} = t
-simplify (Connective c t u) = simplify (connective c t u)
-simplify (Not t) = simplify (notInwards t)
-simplify (And ts) = S.fold (/\) id true (fmap simplify ts)
-simplify (Or ts) = S.fold (\/) id false (fmap simplify ts)
-simplify (Equiv t u) = equiv (simplify t) (simplify u)
-  where equiv t u | isTrue t = u
-                  | isTrue u = t
-                  | isFalse t = nt u
-                  | isFalse u = nt t
-                  | otherwise = Equiv t u
-simplify (ForAll (Bind vs t)) = forAll vs (simplify t)
-  where forAll vs t | Map.null vs = t
-        forAll vs (ForAll (Bind vs' t)) = ForAll (Bind (Map.union vs vs') t)
-        forAll vs t = ForAll (Bind vs t)
-simplify (Exists (Bind vs t)) = exists vs (simplify t)
-  where exists vs t | Map.null vs = t
-        exists vs (Exists (Bind vs' t)) = Exists (Bind (Map.union vs vs') t)
-        exists vs t = Exists (Bind vs t)
-
-----------------------------------------------------------------------
--- Clauses
-
-type CNF = Closed Obligs
-
-data Obligs = Obligs {
-  axioms :: [Input Clause],
-  conjectures :: [[Input Clause]],
-  satisfiable :: String,
-  unsatisfiable :: String
-  }
-
-toObligs :: [Input Clause] -> [[Input Clause]] -> Obligs
-toObligs axioms [] = Obligs axioms [[]] "Satisfiable" "Unsatisfiable"
-toObligs axioms [conjecture] = Obligs axioms [conjecture] "CounterSatisfiable" "Theorem"
-toObligs axioms conjectures = Obligs axioms conjectures "GaveUp" "Theorem"
-
-newtype Clause = Clause (Bind [Literal])
-
-clause :: S.List f => f (Signed Atomic) -> Clause
-clause xs = Clause (bind (S.toList xs))
-
-toForm :: Clause -> Form
-toForm (Clause (Bind vs ls)) = ForAll (Bind vs (Or (S.fromList (map Literal ls))))
-
-toLiterals :: Clause -> [Literal]
-toLiterals (Clause (Bind _ ls)) = ls
-
-----------------------------------------------------------------------
--- Problems
-
-type Tag = BS.ByteString
-
-data Kind = Axiom | Conjecture | Question deriving (Eq, Ord)
-
-data Answer = Satisfiable | Unsatisfiable | NoAnswer NoAnswerReason
-  deriving (Eq, Ord)
-
-instance Show Answer where
-  show Satisfiable = "Satisfiable"
-  show Unsatisfiable = "Unsatisfiable"
-  show (NoAnswer x) = show x
-
-data NoAnswerReason = GaveUp | Timeout deriving (Eq, Ord, Show)
-
-data Input a = Input
-  { tag ::  Tag,
-    kind :: Kind,
-    what :: a }
-
-type Problem a = Closed [Input a]
-
-instance Functor Input where
-  fmap f x = x { what = f (what x) }
-
-----------------------------------------------------------------------
--- Symbolic stuff
-
--- A universe of types with typecase
-data TypeOf a where
-  Form :: TypeOf Form
-  Clause_ :: TypeOf Clause
-  Term :: TypeOf Term
-  Atomic :: TypeOf Atomic
-  Signed :: (Symbolic a, Symbolic (Signed a)) => TypeOf (Signed a)
-  Bind_ :: (Symbolic a, Symbolic (Bind a)) => TypeOf (Bind a)
-  List :: (Symbolic a, Symbolic [a]) => TypeOf [a]
-  Seq :: (Symbolic a, Symbolic (Seq a)) => TypeOf (Seq a)
-  Input_ :: (Symbolic a, Symbolic (Input a)) => TypeOf (Input a)
-  Obligs_ :: TypeOf Obligs
-
-class Symbolic a where
-  typeOf :: a -> TypeOf a
-
-instance Symbolic Form where typeOf _ = Form
-instance Symbolic Clause where typeOf _ = Clause_
-instance Symbolic Term where typeOf _ = Term
-instance Symbolic Atomic where typeOf _ = Atomic
-instance Symbolic a => Symbolic (Signed a) where typeOf _ = Signed
-instance Symbolic a => Symbolic (Bind a) where typeOf _ = Bind_
-instance Symbolic a => Symbolic [a] where typeOf _ = List
-instance Symbolic a => Symbolic (Seq a) where typeOf _ = Seq
-instance Symbolic a => Symbolic (Input a) where typeOf _ = Input_
-instance Symbolic Obligs where typeOf _ = Obligs_
-
--- Generic representations of values.
-data Rep a where
-  Const :: !a -> Rep a
-  Unary :: Symbolic a => (a -> b) -> a -> Rep b
-  Binary :: (Symbolic a, Symbolic b) => (a -> b -> c) -> a -> b -> Rep c
-
--- This inline declaration is crucial so that
--- pattern-matching on a rep degenerates into typecase.
-{-# INLINE rep #-}
-rep :: Symbolic a => a -> Rep a
-rep x =
-  case typeOf x of
-    Form -> rep' x
-    Clause_ -> rep' x
-    Term -> rep' x
-    Atomic -> rep' x
-    Signed -> rep' x
-    Bind_ -> rep' x
-    List -> rep' x
-    Seq -> rep' x
-    Input_ -> rep' x
-    Obligs_ -> rep' x
-
--- Implementation of rep for all types
-class Unpack a where
-  rep' :: a -> Rep a
-
-instance Unpack Form where
-  rep' (Literal l) = Unary Literal l
-  rep' (Not t) = Unary Not t
-  rep' (And ts) = Unary And ts
-  rep' (Or ts) = Unary Or ts
-  rep' (Equiv t u) = Binary Equiv t u
-  rep' (ForAll b) = Unary ForAll b
-  rep' (Exists b) = Unary Exists b
-  rep' (Connective c t u) = Binary (Connective c) t u
-
-instance Unpack Clause where
-  rep' (Clause ls) = Unary Clause ls
-
-instance Unpack Term where
-  rep' t@Var{} = Const t
-  rep' (f :@: ts) = Unary (f :@:) ts
-
-instance Unpack Atomic where
-  rep' (t :=: u) = Binary (:=:) t u
-  rep' (Tru p) = Unary Tru p
-
-instance Symbolic a => Unpack (Signed a) where
-  rep' (Pos x) = Unary Pos x
-  rep' (Neg x) = Unary Neg x
-
-instance Symbolic a => Unpack (Bind a) where
-  rep' (Bind vs x) = Unary (Bind vs) x
-
-instance Symbolic a => Unpack [a] where
-  rep' [] = Const []
-  rep' (x:xs) = Binary (:) x xs
-
-instance Symbolic a => Unpack (Seq a) where
-  rep' S.Nil = Const S.Nil
-  rep' (S.Unit x) = Unary S.Unit x
-  rep' (S.Append x y) = Binary S.Append x y
-
-instance Symbolic a => Unpack (Input a) where
-  rep' (Input tag kind what) = Unary (Input tag kind) what
-
-instance Unpack Obligs where
-  rep' (Obligs ax conj s1 s2) =
-    Binary (\ax' conj' -> Obligs ax' conj' s1 s2) ax conj
-
--- Little generic strategies
-
-{-# INLINE recursively #-}
-recursively :: Symbolic a => (forall a. Symbolic a => a -> a) -> a -> a
-recursively h t =
-  case rep t of
-    Const x -> x
-    Unary f x -> f (h x)
-    Binary f x y -> f (h x) (h y)
-
-{-# INLINE recursivelyM #-}
-recursivelyM :: (Monad m, Symbolic a) => (forall a. Symbolic a => a -> m a) -> a -> m a
-recursivelyM h t =
-  case rep t of
-    Const x -> return x
-    Unary f x -> liftM f (h x)
-    Binary f x y -> liftM2 f (h x) (h y)
-
-{-# INLINE collect #-}
-collect :: (Symbolic a, Monoid b) => (forall a. Symbolic a => a -> b) -> a -> b
-collect h t =
-  case rep t of
-    Const x -> mempty
-    Unary f x -> h x
-    Binary f x y -> h x `mappend` h y
-
-----------------------------------------------------------------------
--- Substitutions
-
-type Subst = NameMap (Name ::: Term)
-
-ids :: Subst
-ids = Map.empty
-
-(|=>) :: Named a => a -> Term -> Subst
-v |=> x = NameMap.singleton (name v ::: x)
-
-(|+|) :: Subst -> Subst -> Subst
-(|+|) = Map.union
-
-subst :: Symbolic a => Subst -> a -> a
-subst s t =
-  case typeOf t of
-    Term -> term t
-    Bind_ -> bind t
-    _ -> generic t
-  where
-    term (Var x)
-      | Just u <- NameMap.lookup (name x) s = rhs u
-    term t = generic t
-
-    bind :: Symbolic a => Bind a -> Bind a
-    bind (Bind vs t) =
-      Bind vs (subst (checkBinder vs (s Map.\\ vs)) t)
-
-    generic :: Symbolic a => a -> a
-    generic t = recursively (subst s) t
-
-----------------------------------------------------------------------
--- Functions operating on symbolic terms
-
-free :: Symbolic a => a -> NameMap Variable
-free t
-  | Term <- typeOf t,
-    Var x <- t        = var x
-  | Bind_ <- typeOf t = bind t
-  | otherwise         = collect free t
-  where
-    var :: Variable -> NameMap Variable
-    var x = NameMap.singleton x
-
-    bind :: Symbolic a => Bind a -> NameMap Variable
-    bind (Bind vs t) = free t Map.\\ vs
-
-ground :: Symbolic a => a -> Bool
-ground = Map.null . free
-
-bind :: Symbolic a => a -> Bind a
-bind x = Bind (free x) x
-
--- Helper function for collecting information from terms and binders.
-termsAndBinders :: forall a b.
-                   Symbolic a =>
-                   (Term -> Seq b) ->
-                   (forall a. Symbolic a => Bind a -> Seq b) ->
-                   a -> Seq b
-termsAndBinders term bind = aux where
-  aux :: Symbolic c => c -> Seq b
-  aux t =
-    collect aux t `S.append`
-    case typeOf t of
-      Term -> term t
-      Bind_ -> bind t
-      _ -> S.Nil
-
-names :: Symbolic a => a -> [Name]
-names = nub . termsAndBinders term bind where
-  term t = return (name t) `mappend` return (name (typ t))
-
-  bind :: Symbolic a => Bind a -> Seq Name
-  bind (Bind vs _) = S.fromList (map name (NameMap.toList vs))
-
-types :: Symbolic a => a -> [Type]
-types = nub . termsAndBinders term bind where
-  term t = return (typ t)
-
-  bind :: Symbolic a => Bind a -> Seq Type
-  bind (Bind vs _) = S.fromList (map typ (NameMap.toList vs))
-
-types' :: Symbolic a => a -> [Type]
-types' = filter (/= O) . types
-
-terms :: Symbolic a => a -> [Term]
-terms = nub . termsAndBinders term mempty where
-  term t = return t
-
-vars :: Symbolic a => a -> [Variable]
-vars = nub . termsAndBinders term bind where
-  term (Var x) = return x
-  term _ = mempty
-
-  bind :: Symbolic a => Bind a -> Seq Variable
-  bind (Bind vs _) = S.fromList (NameMap.toList vs)
-
-functions :: Symbolic a => a -> [Function]
-functions = nub . termsAndBinders term mempty where
-  term (f :@: _) = return f
-  term _ = mempty
-
-isFof :: Symbolic a => a -> Bool
-isFof f = length (types' f) <= 1
-
-uniqueNames :: Symbolic a => a -> NameM a
-uniqueNames t = evalStateT (aux Map.empty t) (free t)
-  where aux :: Symbolic a => Subst -> a -> StateT (NameMap Variable) NameM a
-        aux s t =
-          case typeOf t of
-            Term -> term s t
-            Bind_ -> bind s t
-            _ -> generic s t
-
-        term :: Subst -> Term -> StateT (NameMap Variable) NameM Term
-        term s t@(Var x) = do
-          case NameMap.lookup (name x) s of
-            Nothing -> return t
-            Just (_ ::: u) -> return u
-        term s t = generic s t
-
-        bind :: Symbolic a => Subst -> Bind a -> StateT (NameMap Variable) NameM (Bind a)
-        bind s (Bind vs x) = do
-          used <- get
-          let (stale, fresh) = partition (`NameMap.member` used) (NameMap.toList vs)
-          stale' <- sequence [ lift (newSymbol x t) | x ::: t <- stale ]
-          put (used `Map.union` NameMap.fromList fresh `Map.union` NameMap.fromList stale')
-          case stale of
-            [] -> fmap (Bind vs) (aux s x)
-            _ ->
-              do
-                let s' = NameMap.fromList [name x ::: Var y | (x, y) <- stale `zip` stale'] `Map.union` s
-                    vs' = NameMap.fromList (stale' ++ fresh)
-                fmap (Bind vs') (aux s' x)
-
-        generic :: Symbolic a => Subst -> a -> StateT (NameMap Variable) NameM a
-        generic s t = recursivelyM (aux s) t
-
--- Force a value.
-force :: Symbolic a => a -> a
-force x = rnf x `seq` x
-  where rnf :: Symbolic a => a -> ()
-        rnf x =
-          case rep x of
-            Const !_ -> ()
-            Unary _ x -> rnf x
-            Binary _ x y -> rnf x `seq` rnf y
-
--- Check that there aren't two nested binders binding the same variable
-check :: Symbolic a => a -> a
-check x | not debugging = x
-        | check' (free x) x = x
-        | otherwise = error "Form.check: invariant broken"
-  where check' :: Symbolic a => NameMap Variable -> a -> Bool
-        check' vars t =
-          case typeOf t of
-            Term -> term vars t
-            Bind_ -> bind vars t
-            _ -> generic vars t
-
-        term :: NameMap Variable -> Term -> Bool
-        term vars (Var x) = x `NameMap.member` vars
-        term vars t = generic vars t
-
-        bind :: Symbolic a => NameMap Variable -> Bind a -> Bool
-        bind vars (Bind vs t) =
-          Map.null (vs `Map.intersection` vars) &&
-          check' (vs `Map.union` vars) t
-
-        generic :: Symbolic a => NameMap Variable -> a -> Bool
-        generic vars = getAll . collect (All . generic vars)
-
--- Check that a binder doesn't capture variables from a substitution.
-checkBinder :: NameMap Variable -> Subst -> Subst
-checkBinder vs s | not debugging = s
-                 | Map.null (free [ t | _ ::: t <- NameMap.toList s ] `Map.intersection` vs) = s
-                 | otherwise = error "Form.checkBinder: capturing substitution"
-
--- Reestablish sharing in a formula.
-type ShareState = (NameMap Type, NameMap Variable, NameMap Function)
-
-share :: Symbolic a => a -> a
-share x = evalState (shareM x) initial
-  where initial :: ShareState
-        initial = (Map.empty, Map.empty, Map.empty)
-
-        shareM :: Symbolic a => a -> State ShareState a
-        shareM t =
-          case typeOf t of
-            Term -> term t
-            Bind_ -> bind t
-            _ -> recursivelyM shareM t
-
-        bind :: Symbolic a => Bind a -> State ShareState (Bind a)
-        bind (Bind vs x) =
-          liftM2 Bind (mapM var vs) (shareM x)
-
-        term :: Term -> State ShareState Term
-        term (Var x) = fmap Var (var x)
-        term (f :@: ts) = liftM2 (:@:) (fun f) (mapM term ts)
-
-        fun :: Function -> State ShareState Function
-        fun (f ::: FunType args res) = do
-          args' <- mapM type_ args
-          res' <- type_ res
-          memo funAccessor (f ::: FunType args' res')
-
-        var :: Variable -> State ShareState Variable
-        var (x ::: ty) = fmap (x :::) (type_ ty) >>= memo varAccessor
-
-        type_ :: Type -> State ShareState Type
-        type_ = memo typeAccessor
-
-        typeAccessor = (\(x, y, z) -> x, \x (_, y, z) -> (x, y, z))
-        varAccessor = (\(x, y, z) -> y, \y (x, _, z) -> (x, y, z))
-        funAccessor = (\(x, y, z) -> z, \z (x, y, _) -> (x, y, z))
-
-        memo :: Named a =>
-                (ShareState -> NameMap a,
-                 NameMap a -> ShareState -> ShareState) ->
-                a -> State ShareState a
-        memo (get_, put_) x = do
-          m <- gets get_
-          case NameMap.lookup (name x) m of
-            Nothing -> do
-              modify (put_ (NameMap.insert x m))
-              return x
-            Just y ->
-              return y
-
--- Apply a function to each type, while preserving sharing.
-mapType :: Symbolic a => (Type -> Type) -> a -> a
-mapType f = share . mapType'
-  where mapType' :: Symbolic a => a -> a
-        mapType' t =
-          case typeOf t of
-            Term -> term t
-            Bind_ -> bind t
-            _ -> recursively mapType' t
-
-        bind :: Symbolic a => Bind a -> Bind a
-        bind (Bind vs t) = Bind (fmap var vs) (mapType' t)
-
-        term (f :@: ts) = fun f :@: map term ts
-        term (Var x) = Var (var x)
-
-        var (x ::: ty) = x ::: f ty
-        fun (x ::: FunType args res) = x ::: FunType (map f args) (f res)
diff --git a/Jukebox/GuessModel.hs b/Jukebox/GuessModel.hs
deleted file mode 100644
--- a/Jukebox/GuessModel.hs
+++ /dev/null
@@ -1,121 +0,0 @@
-{-# LANGUAGE GADTs, PatternGuards #-}
-module Jukebox.GuessModel where
-
-import Control.Monad
-import qualified Data.ByteString.Char8 as BS
-import Jukebox.Name
-import Jukebox.Form
-import Jukebox.Clausify hiding (cnf)
-import Jukebox.TPTP.Print
-import Jukebox.TPTP.ParseSnippet
-import Jukebox.Utils
-
-data Universe = Peano | Trees
-
-universe :: Universe -> Type -> NameM ([Function], [Form])
-universe Peano = peano
-universe Trees = trees
-
-peano i = do
-  zero <- newFunction "zero" [] i
-  succ <- newFunction "succ" [i] i
-  pred <- newFunction "pred" [i] i
-  let types = [("$i", i)]
-      funs = [("zero", zero),
-              ("succ", succ),
-              ("pred", pred)]
-  
-  prelude <- mapM (cnf types funs) [
-    "zero != succ(X)",
-    "pred(succ(X)) = X"
-    ]
-  return ([zero, succ], prelude)
-
-trees i = do
-  nil <- newFunction "nil" [] i
-  bin <- newFunction "bin" [i, i] i
-  left <- newFunction "left" [i] i
-  right <- newFunction "right" [i] i
-  let types = [("$i", i)]
-      funs = [("nil", nil),
-              ("bin", bin),
-              ("left", left),
-              ("right", right)]
-  
-  prelude <- mapM (cnf types funs) [
-    "nil != bin(X,Y)",
-    "left(bin(X,Y)) = X",
-    "right(bin(X,Y)) = Y"
-    ]
-  return ([nil, bin], prelude)
-
-guessModel :: [String] -> Universe -> Problem Form -> Problem Form
-guessModel expansive univ prob = close prob $ \forms -> do
-  let i = ind forms
-  answerType <- newType "answer"
-  answer <- newFunction "$answer" [answerType] O
-  let withExpansive f func = f func (BS.unpack (base (name func)) `elem` expansive) answer
-  (constructors, prelude) <- universe univ i
-  program <- fmap concat (mapM (withExpansive (function constructors)) (functions forms))
-  return (map (Input (BS.pack "adt") Axiom) prelude ++
-          map (Input (BS.pack "program") Axiom) program ++
-          forms)
-
-ind :: Symbolic a => a -> Type
-ind x =
-  case types' x of
-    [ty] -> ty
-    [] -> Type nameI Infinite Infinite
-    _ -> error "GuessModel: can't deal with many-typed problems"
-
-function :: [Function] -> Function -> Bool -> Function -> NameM [Form]
-function constructors f expansive answerP = fmap concat $ do
-  argss <- cases constructors (funArgs f)
-  forM argss $ \args -> do
-    fname <- newFunction ("exhausted_" ++ BS.unpack (base (name f)) ++ "_case")
-               [] (head (funArgs answerP))
-    let answer = Literal (Pos (Tru (answerP :@: [fname :@: []])))
-    let theRhss = rhss constructors args f expansive answer
-    alts <- forM theRhss $ \rhs -> do
-      pred <- newFunction (concat (lines (prettyFormula rhs))) [] O
-      return (Literal (Pos (Tru (pred :@: []))))
-    return $
-      disj alts:
-      [ closeForm (Connective Implies alt rhs)
-      | (alt, rhs) <- zip alts theRhss ]
-
-rhss :: [Function] -> [Term] -> Function -> Bool -> Form -> [Form]
-rhss constructors args f expansive answer =
-  case typ f of
-    O ->
-      Literal (Pos (Tru (f :@: args))):
-      Literal (Neg (Tru (f :@: args))):
-      map its (map (f :@:) (recursive args))
-    _ | expansive -> map its (usort (unconditional ++ constructor))
-      | otherwise -> map its (usort unconditional) ++ [answer]
-  where recursive [] = []
-        recursive (a:as) = reduce a ++ map (a:) (recursive as)
-          where reduce (f :@: xs) = [ x:as' | x <- xs, as' <- as:recursive as ]
-                reduce _ = []
-        constructor = [ c :@: xs
-                      | c <- constructors,
-                        xs <- sequence (replicate (arity c) unconditional) ]
-        
-        subterm = terms args
-        its t = f :@: args .=. t
-        unconditional = map (f :@:) (recursive args) ++ subterm
-
-cases :: [Function] -> [Type] -> NameM [[Term]]
-cases constructors [] = return [[]]
-cases constructors (ty:tys) = do
-  ts <- cases1 constructors ty
-  tss <- cases constructors tys
-  return (liftM2 (:) ts tss)
-
-cases1 :: [Function] -> Type -> NameM [Term]
-cases1 constructors ty = do
-  let maxArity = maximum (map arity constructors)
-      varNames = take maxArity (cycle ["X", "Y", "Z"])
-  vars <- mapM (flip newSymbol ty) varNames
-  return [ c :@: take (arity c) (map Var vars)
-         | c <- constructors ]
diff --git a/Jukebox/HighSat.hs b/Jukebox/HighSat.hs
deleted file mode 100644
--- a/Jukebox/HighSat.hs
+++ /dev/null
@@ -1,114 +0,0 @@
-{-# LANGUAGE BangPatterns, GeneralizedNewtypeDeriving #-}
-module Jukebox.HighSat where
-
-import MiniSat hiding (neg)
-import qualified MiniSat
-import qualified Jukebox.Seq as Seq
-import Jukebox.Seq(Seq, List)
-import Jukebox.Form(Signed(..), neg)
-import qualified Jukebox.Map as Map
-import Jukebox.Map(Map)
-import Control.Monad.State.Strict
-import Control.Monad.Reader
-import Control.Monad.Trans
-import Data.Hashable
-import Data.Traversable hiding (mapM, sequence)
-import Control.Applicative
-import Data.Maybe
-import Data.List(partition)
-import Control.Applicative
-
-newtype Sat1 a b = Sat1 { runSat1_ :: ReaderT Solver (ReaderT (Watch a) (StateT (Map a Lit) IO)) b } deriving (Functor, Applicative, Monad, MonadIO)
-newtype Sat a b c = Sat { runSat_ :: ReaderT (Watch a) (StateT (Map b (SatState a)) IO) c } deriving (Functor, Applicative, Monad, MonadIO)
-data SatState a = SatState Solver (Map a Lit)
-type Watch a = a -> Sat1 a ()
-
-data Form a
-  = Lit (Signed a)
-  | And (Seq (Form a))
-  | Or (Seq (Form a))
-
-nt :: Form a -> Form a
-nt (Lit x) = Lit (neg x)
-nt (And xs) = Or (fmap nt xs)
-nt (Or xs) = And (fmap nt xs)
-
-conj, disj :: List f => f (Form a) -> Form a
-conj = And . Seq.fromList
-disj = Or . Seq.fromList
-
-true, false :: Form a
-true = And Seq.Nil
-false = Or Seq.Nil
-
-unique :: List f => f (Form a) -> Form a
-unique = u . Seq.toList
-  where u [x] = true
-        u (x:xs) = conj [disj [nt x, conj (map nt xs)],
-                         u xs]
-
-runSat :: (Hashable b, Ord b) => Watch a -> [b] -> Sat a b c -> IO c
-runSat w idxs x = go idxs Map.empty
-  where go [] m = evalStateT (runReaderT (runSat_ x) w) m
-        go (idx:idxs) m =
-          withNewSolver $ \s -> go idxs (Map.insert idx (SatState s Map.empty) m)
-
-runSat1 :: (Ord a, Hashable a) => Watch a -> Sat1 a b -> IO b
-runSat1 w x = runSat w [()] (atIndex () x)
-
-atIndex :: (Ord a, Hashable a, Ord b, Hashable b) => b -> Sat1 a c -> Sat a b c
-atIndex !idx m = do
-  watch <- Sat ask
-  SatState s ls <- Sat (gets (Map.findWithDefault (error "withSolver: index not found") idx))
-  (x, ls') <- liftIO (runStateT (runReaderT (runReaderT (runSat1_ m) s) watch) ls)
-  Sat (modify (Map.insert idx (SatState s ls')))
-  return x
-
-solve :: (Ord a, Hashable a) => [Signed a] -> Sat1 a Bool
-solve xs = do
-  s <- Sat1 ask
-  ls <- mapM lit xs
-  liftIO (MiniSat.solve s ls)
-
-model :: (Ord a, Hashable a) => Sat1 a (a -> Bool)
-model = do
-  s <- Sat1 ask
-  m <- Sat1 (lift get)
-  vals <- liftIO (traverse (MiniSat.modelValue s) m)
-  return (\v -> fromMaybe False (Map.findWithDefault Nothing v vals))
-
-modelValue :: (Ord a, Hashable a) => a -> Sat1 a Bool
-modelValue x = do
-  s <- Sat1 ask
-  l <- var x
-  Just b <- liftIO (MiniSat.modelValue s l)
-  return b
-
-addForm :: (Ord a, Hashable a) => Form a -> Sat1 a ()
-addForm f = do
-  s <- Sat1 ask
-  cs <- flatten f
-  liftIO (Seq.mapM (MiniSat.addClause s . Seq.toList) cs)
-  return ()
-
-flatten :: (Ord a, Hashable a) => Form a -> Sat1 a (Seq (Seq Lit))
-flatten (Lit l) = fmap (Seq.Unit . Seq.Unit) (lit l)
-flatten (And fs) = fmap Seq.concat (Seq.mapM flatten fs)
-flatten (Or fs) = fmap (fmap Seq.concat . Seq.sequence) (Seq.mapM flatten fs)
-
-lit :: (Ord a, Hashable a) => Signed a -> Sat1 a Lit
-lit (Pos x) = var x
-lit (Neg x) = liftM MiniSat.neg (var x)
-
-var :: (Ord a, Hashable a) => a -> Sat1 a Lit
-var x = do
-  s <- Sat1 ask
-  m <- Sat1 get
-  case Map.lookup x m of
-    Nothing -> do
-      l <- liftIO (MiniSat.newLit s)
-      Sat1 (put (Map.insert x l m))
-      w <- Sat1 (lift ask)
-      w x
-      return l
-    Just l -> return l
diff --git a/Jukebox/InferTypes.hs b/Jukebox/InferTypes.hs
deleted file mode 100644
--- a/Jukebox/InferTypes.hs
+++ /dev/null
@@ -1,82 +0,0 @@
-{-# LANGUAGE TypeOperators, GADTs #-}
-module Jukebox.InferTypes where
-
-import Control.Monad
-import Jukebox.Form
-import Jukebox.Name
-import qualified Jukebox.NameMap as NameMap
-import Jukebox.NameMap(NameMap)
-import Jukebox.UnionFind hiding (rep)
-
-type Function' = Name ::: ([Type'], Type')
-type Variable' = Name ::: Type'
-type Type' = Name ::: Type
-
-inferTypes :: [Input Clause] -> NameM ([Input Clause], Type -> Type)
-inferTypes prob = do
-  funMap <-
-    fmap NameMap.fromList . sequence $
-      [ do res <- newName (typ f)
-           args <- mapM newName (funArgs f)
-           return (name f :::
-                   (zipWith (:::) args (funArgs f),
-                    res ::: typ f))
-      | f <- functions prob ]
-  varMap <-
-    fmap NameMap.fromList . sequence $
-      [ do ty <- newName (typ v)
-           return (name v ::: (ty ::: typ v))
-      | v <- vars prob ]
-  
-  let tyMap = NameMap.fromList $
-              concat [ res:args | _ ::: (args, res) <- NameMap.toList funMap ] ++
-              [ ty | _ ::: ty <- NameMap.toList varMap ]
-  
-  let (prob', rep) = solve funMap varMap prob
-      rep' ty = rhs (NameMap.lookup_ (rep (name ty)) tyMap)
-  
-  return (prob', rep')
-
-solve :: NameMap Function' -> NameMap Variable' ->
-         [Input Clause] -> ([Input Clause], Name -> Name)
-solve funMap varMap prob = (prob', rep)
-  where prob' = share (aux prob)
-        aux :: Symbolic a => a -> a
-        aux t =
-          case typeOf t of
-            Bind_ -> bind t
-            Term -> term t
-            _ -> recursively aux t
-
-        bind :: Symbolic a => Bind a -> Bind a
-        bind (Bind vs t) = Bind (fmap var vs) (aux t)
-
-        term (f :@: ts) = fun f :@: map term ts
-        term (Var x) = Var (var x)
-
-        fun (f ::: _) =
-          let (args, res) = rhs (NameMap.lookup_ f funMap)
-          in f ::: FunType (map type_ args) (type_ res)
-
-        var (x ::: _) = x ::: type_ (rhs (NameMap.lookup_ x varMap))
-
-        type_ (name ::: _) 
-          | name == nameO = O
-          | otherwise = Type (rep name) Infinite Infinite
-
-        rep = evalUF initial $ do
-          generate funMap varMap prob
-          reps
-
-generate :: NameMap Function' -> NameMap Variable' -> [Input Clause] -> UF Name ()
-generate funMap varMap cs = mapM_ (mapM_ atomic) lss
-  where lss = map (map the . toLiterals . what) cs
-        atomic (Tru p) = void (term p)
-        atomic (t :=: u) = do { t' <- term t; u' <- term u; t' =:= u'; return () }
-        term (Var x) = return y
-          where _ ::: (y ::: _) = NameMap.lookup_ x varMap
-        term (f :@: xs) = do
-          ys <- mapM term xs
-          let _ ::: (zs, r) = NameMap.lookup_ f funMap
-          zipWithM_ (=:=) ys (map lhs zs)
-          return (lhs r)
diff --git a/Jukebox/Map.hs b/Jukebox/Map.hs
deleted file mode 100644
--- a/Jukebox/Map.hs
+++ /dev/null
@@ -1,28 +0,0 @@
-{-# LANGUAGE NoMonomorphismRestriction #-}
-module Jukebox.Map where
-
-import qualified Data.HashMap.Lazy as H
-
-type Map a b = H.HashMap a b
-
-fromList = H.fromList
-toList = H.toList
-insertWith = H.insertWith
-empty = H.empty
-findWithDefault = H.lookupDefault
-lookup = H.lookup
-insert = H.insert
-delete = H.delete
-elems = H.elems
-union = H.union
-intersection = H.intersection
-null = H.null
-m ! x = H.lookupDefault (error "Map.!: key not found") x m
-
-member x m =
-  case H.lookup x m of
-    Nothing -> False
-    Just{} -> True
-
-m1 \\ m2 =
-  H.foldrWithKey (\k v m -> H.delete k m) m1 m2
diff --git a/Jukebox/Monotonox/Monotonicity.hs b/Jukebox/Monotonox/Monotonicity.hs
deleted file mode 100644
--- a/Jukebox/Monotonox/Monotonicity.hs
+++ /dev/null
@@ -1,82 +0,0 @@
-{-# LANGUAGE TypeOperators #-}
-module Jukebox.Monotonox.Monotonicity where
-
-import Prelude hiding (lookup)
-import Jukebox.Name
-import Jukebox.Form hiding (Form, clause, true, false, conj, disj)
-import Jukebox.HighSat
-import Jukebox.NameMap as NameMap
-import Jukebox.Utils
-import Data.Hashable
-import Control.Monad
-
-data Extension = TrueExtend | FalseExtend | CopyExtend deriving Show
-
-data Var = FalseExtended Function | TrueExtended Function deriving (Eq, Ord)
-
-instance Hashable Var where
-  hashWithSalt s = hashWithSalt s . convert
-    where convert (FalseExtended x) = Left x
-          convert (TrueExtended x) = Right x
-
-annotateMonotonicity :: Problem Clause -> IO (Problem Clause)
-annotateMonotonicity prob = do
-  m <- monotone (map what (open prob))
-  let f O = O
-      f ty =
-        case lookup (name ty) m of
-          Nothing -> ty
-          Just{} -> ty { tmonotone = Finite 0 }
-  return (fmap (mapType f) prob)
-
-monotone :: [Clause] -> IO (NameMap (Type ::: Maybe (NameMap (Function ::: Extension))))
-monotone cs = runSat watch tys $ do
-  let fs = functions cs
-  mapM_ (clause . toLiterals) cs
-  fmap NameMap.fromList . forM tys $ \ty -> atIndex ty $ do
-    r <- solve []
-    case r of
-      False -> return (ty ::: Nothing)
-      True -> do
-        m <- model
-        return (ty ::: Just (fromModel fs ty m))
-  where watch (FalseExtended f) =
-          addForm (disj [Lit (Neg (FalseExtended f)),
-                         Lit (Neg (TrueExtended f))])
-        watch _ = return ()
-        tys = types' cs
-
-fromModel :: [Function] -> Type -> (Var -> Bool) -> NameMap (Function ::: Extension)
-fromModel fs ty m = NameMap.fromList [ f ::: extension f m | f <- fs, typ f == O, ty `elem` args (rhs f) ]
-
-extension :: Function -> (Var -> Bool) -> Extension
-extension f m =
-  case (m (FalseExtended f), m (TrueExtended f)) of
-    (False, False) -> CopyExtend
-    (True, False) -> FalseExtend
-    (False, True) -> TrueExtend
-
-clause :: [Literal] -> Sat Var Type ()
-clause ls = mapM_ (literal ls) ls
-
-literal :: [Literal] -> Literal -> Sat Var Type ()
-literal ls (Pos (t :=: u)) = atIndex (typ t) $ do
-  addForm (safe ls t)
-  addForm (safe ls u)
-literal ls (Neg (_ :=: _)) = return ()
-literal ls (Pos (Tru (p :@: ts))) =
-  forM_ ts $ \t -> atIndex (typ t) $ addForm (disj [safe ls t, Lit (Neg (FalseExtended p))])
-literal ls (Neg (Tru (p :@: ts))) =
-  forM_ ts $ \t -> atIndex (typ t) $ addForm (disj [safe ls t, Lit (Neg (TrueExtended p))])
-
-safe :: [Literal] -> Term -> Form Var
-safe ls (Var x) = disj [ guards l x | l <- ls ]
-safe _ _ = true
-
-guards :: Literal -> Variable -> Form Var
-guards (Neg (Var _ :=: Var _)) _ = error "Monotonicity.guards: found a variable inequality X!=Y after clausification"
-guards (Neg (Var x :=: _)) y | x == y = true
-guards (Neg (_ :=: Var x)) y | x == y = true
-guards (Pos (Tru (p :@: ts))) x | Var x `elem` ts = Lit (Pos (TrueExtended p))
-guards (Neg (Tru (p :@: ts))) x | Var x `elem` ts = Lit (Pos (FalseExtended p))
-guards _ _ = false
diff --git a/Jukebox/Monotonox/ToFOF.hs b/Jukebox/Monotonox/ToFOF.hs
deleted file mode 100644
--- a/Jukebox/Monotonox/ToFOF.hs
+++ /dev/null
@@ -1,191 +0,0 @@
-{-# LANGUAGE GADTs, PatternGuards #-}
-module Jukebox.Monotonox.ToFOF where
-
-import Jukebox.Clausify(split, removeEquiv, run, withName)
-import Jukebox.Name
-import qualified Jukebox.NameMap as NameMap
-import Jukebox.Form
-import Jukebox.Options
-import qualified Data.ByteString.Char8 as BS
-import Control.Monad hiding (guard)
-import Data.Monoid
-
-data Scheme = Scheme {
-  makeFunction :: Type -> NameM Function,
-  scheme1 :: (Type -> Bool) -> (Type -> Function) -> Scheme1
-  }
-
-data Scheme1 = Scheme1 {
-  forAll :: Bind Form -> Form,
-  exists :: Bind Form -> Form,
-  equals :: Term -> Term -> Form,
-  funcAxiom :: Function -> NameM Form,
-  typeAxiom :: Type -> NameM Form
-  }
-
-guard :: Scheme1 -> (Type -> Bool) -> Input Form -> Input Form
-guard scheme mono (Input t k f) = Input t k (aux (pos k) f)
-  where aux pos (ForAll (Bind vs f))
-          | pos = forAll scheme (Bind vs (aux pos f))
-          | otherwise = Not (exists scheme (Bind vs (Not (aux pos f))))
-        aux pos (Exists (Bind vs f))
-          | pos = exists scheme (Bind vs (aux pos f))
-          | otherwise = Not (forAll scheme (Bind vs (Not (aux pos f))))
-        aux pos (Literal (Pos (t :=: u)))
-          | not (mono (typ t)) = equals scheme t u
-        aux pos (Literal (Neg (t :=: u)))
-          | not (mono (typ t)) = Not (equals scheme t u)
-        aux pos l@Literal{} = l
-        aux pos (Not f) = Not (aux (not pos) f)
-        aux pos (And fs) = And (fmap (aux pos) fs)
-        aux pos (Or fs) = Or (fmap (aux pos) fs)
-        aux pos (Equiv _ _) = error "ToFOF.guard: equiv should have been eliminated"
-        aux pos (Connective _ _ _) = error "ToFOF.guard: connective should have been eliminated"
-        pos Axiom = True
-        pos Conjecture = False
-
-translate, translate1 :: Scheme -> (Type -> Bool) -> Problem Form -> Problem Form
-translate1 scheme mono f = close f $ \inps -> do
-  let tys = types inps
-      funcs = functions inps
-      -- Hardly any use adding guards if there's only one type.
-      mono' | length tys == 1 = const True
-            | otherwise = mono
-  typeFuncs <- mapM (makeFunction scheme) tys
-  let typeMap = NameMap.fromList (zipWith (:::) tys typeFuncs)
-      lookupType ty =
-        case NameMap.lookup (name ty) typeMap of
-          Just (_ ::: f) -> f
-          Nothing -> error "ToFOF.translate: type not found"
-      scheme1' = scheme1 scheme mono' lookupType
-  funcAxioms <- mapM (funcAxiom scheme1') funcs
-  typeAxioms <- mapM (typeAxiom scheme1') tys
-  let axioms =
-        map (simplify . ForAll . bind) . split . simplify . foldr (/\) true $
-          funcAxioms ++ typeAxioms
-  return $
-    [ Input (BS.pack ("types" ++ show i)) Axiom axiom | (axiom, i) <- zip axioms [1..] ] ++
-    map (guard scheme1' mono') inps
-
-translate scheme mono f =
-  let f' =
-        close f $ \inps -> do
-          forM inps $ \(Input tag kind f) -> do
-            let prepare f = fmap (foldr (/\) true) (run (withName tag (removeEquiv (simplify f))))
-            fmap (Input tag kind) $
-              case kind of
-                Axiom -> prepare f
-                Conjecture -> fmap notInwards (prepare (nt f))
-      typeI = Type nameI (Finite 0) Infinite
-  in close (translate1 scheme mono f') (return . mapType (const typeI))
-
--- Typing functions.
-
-tagsFlags :: OptionParser Bool
-tagsFlags =
-  bool "more-axioms"
-    ["Add extra typing axioms for function arguments,",
-     "when using typing tags.",
-     "These are unnecessary for completeness but may help (or hinder!) the prover."]
-
-tags :: Bool -> Scheme
-tags moreAxioms = Scheme
-  { makeFunction = \ty ->
-      newFunction (BS.append (BS.pack "to_") (baseName ty)) [ty] ty,
-    scheme1 = tags1 moreAxioms }
-
-tags1 :: Bool -> (Type -> Bool) -> (Type -> Function) -> Scheme1
-tags1 moreAxioms mono fs = Scheme1
-  { forAll = ForAll,
-    exists = \(Bind vs f) ->
-       let bound = foldr (/\) true (map guard (NameMap.toList vs))
-           guard v | mono (typ v) = true
-                   | otherwise = Literal (Pos (fs (typ v) :@: [Var v] :=: Var v))
-       in Exists (Bind vs (simplify bound /\ f)),
-    equals =
-      \t u ->
-        let protect t@Var{} = fs (typ t) :@: [t]
-            protect t = t
-        in Literal (Pos (protect t :=: protect u)),
-    funcAxiom = tagsAxiom moreAxioms mono fs,
-    typeAxiom = \ty -> if moreAxioms then tagsAxiom False mono fs (fs ty) else tagsExists mono ty (fs ty) }
-
-tagsAxiom :: Bool -> (Type -> Bool) -> (Type -> Function) -> Function -> NameM Form
-tagsAxiom moreAxioms mono fs f@(_ ::: FunType args res) = do
-  vs <- forM args $ \ty ->
-    fmap Var (newSymbol "X" ty)
-  let t = f :@: vs
-      at n f xs = take n xs ++ [f (xs !! n)] ++ drop (n+1) xs
-      tag t = fs (typ t) :@: [t]
-      equate (ty, t') | mono ty = true
-                      | otherwise = t `eq` t'
-      t `eq` u | typ t == O = Literal (Pos (Tru t)) `Equiv` Literal (Pos (Tru u))
-               | otherwise = Literal (Pos (t :=: u))
-      ts = (typ t, tag t):
-           [ (typ (vs !! n), f :@: at n tag vs)
-           | moreAxioms,
-             n <- [0..length vs-1] ]
-  return (foldr (/\) true (map equate ts))
-
-tagsExists :: (Type -> Bool) -> Type -> Function -> NameM Form
-tagsExists mono ty f
-  | mono ty = return true
-  | otherwise = do
-      v <- fmap Var (newSymbol "X" ty)
-      return (Exists (bind (Literal (Pos (f :@: [v] :=: v)))))
-
--- Typing predicates.
-
-guards :: Scheme
-guards = Scheme
-  { makeFunction = \ty ->
-      newFunction (BS.append (BS.pack "is_") (baseName ty)) [ty] O,
-    scheme1 = guards1 }
-
-guards1 :: (Type -> Bool) -> (Type -> Function) -> Scheme1
-guards1 mono ps = Scheme1
-  { forAll = \(Bind vs f) ->
-       let bound = foldr (/\) true (map guard (NameMap.toList vs))
-           guard v | mono (typ v) = true
-                   | not (naked True v f) = true
-                   | otherwise = Literal (Pos (Tru (ps (typ v) :@: [Var v])))
-       in ForAll (Bind vs (simplify (Not bound) \/ f)),
-    exists = \(Bind vs f) ->
-       let bound = foldr (/\) true (map guard (NameMap.toList vs))
-           guard v | mono (typ v) = true
---                   | not (naked True v f) = true
-                   | otherwise = Literal (Pos (Tru (ps (typ v) :@: [Var v])))
-       in Exists (Bind vs (simplify bound /\ f)),
-    equals = \t u -> Literal (Pos (t :=: u)),
-    funcAxiom = guardsAxiom mono ps,
-    typeAxiom = guardsTypeAxiom mono ps }
-
-naked :: Symbolic a => Bool -> Variable -> a -> Bool
-naked pos v f
-  | Form <- typeOf f,
-    Not f' <- f = naked (not pos) v f'
-  | Signed <- typeOf f,
-    Pos f' <- f = naked pos v f'
-  | Signed <- typeOf f,
-    Neg f' <- f = naked (not pos) v f'
-  | Atomic <- typeOf f,
-    t :=: u <- f,
-    pos = t == Var v || u == Var v
-  | Bind_ <- typeOf f,
-    Bind vs f' <- f = not (NameMap.member v vs) && naked pos v f'
-  | otherwise = getAny (collect (Any . naked pos v) f)
-
-guardsAxiom :: (Type -> Bool) -> (Type -> Function) -> Function -> NameM Form
-guardsAxiom mono ps f@(_ ::: FunType args res)
-  | mono res = return true
-  | otherwise = do
-    vs <- forM args $ \ty ->
-      fmap Var (newSymbol "X" ty)
-    return (Literal (Pos (Tru (ps res :@: [f :@: vs]))))
-
-guardsTypeAxiom :: (Type -> Bool) -> (Type -> Function) -> Type -> NameM Form
-guardsTypeAxiom mono ps ty
-  | mono ty = return true
-  | otherwise = do
-    v <- fmap Var (newSymbol "X" ty)
-    return (Exists (bind (Literal (Pos (Tru (ps ty :@: [v]))))))
diff --git a/Jukebox/Name.hs b/Jukebox/Name.hs
deleted file mode 100644
--- a/Jukebox/Name.hs
+++ /dev/null
@@ -1,153 +0,0 @@
-{-# LANGUAGE TypeOperators, GeneralizedNewtypeDeriving, FlexibleInstances, DeriveDataTypeable #-}
-module Jukebox.Name(
-  Name, uniqueId, base,
-  stringBaseName,
-  unsafeMakeName,
-  (:::)(..), lhs, rhs,
-  Named(..),
-  Closed, close, close_, closedIO, open, closed0, stdNames, nameO, nameI, NameM, newName,
-  unsafeClose, maxIndex, supply,
-  uniquify) where
-
-import qualified Data.ByteString.Char8 as BS
-import Data.Hashable
-import qualified Jukebox.Map as Map
-import Jukebox.Utils
-import Data.List
-import Data.Ord
-import Data.Int
-import Data.Typeable
-import Control.Monad.State.Strict
-import Control.Applicative
-
-data Name =
-  Name {
-    uniqueId :: {-# UNPACK #-} !Int64,
-    base :: BS.ByteString } deriving Typeable
-
-unsafeMakeName = Name
-
-instance Eq Name where
-  x == y = uniqueId x == uniqueId y
-
-instance Ord Name where
-  compare = comparing uniqueId
-
-instance Hashable Name where
-  hashWithSalt s = hashWithSalt s . uniqueId
-
-instance Show Name where
-  show Name { uniqueId = uniqueId, base = base } =
-    BS.unpack base ++ show uniqueId
-
-class Named a where
-  name :: a -> Name
-  baseName :: a -> BS.ByteString
-  baseName = base . name
-
-stringBaseName :: Named a => a -> String
-stringBaseName = BS.unpack . baseName
-
-instance Named BS.ByteString where
-  name = error "Name.name: used a ByteString as a name"
-  baseName = id
-
-instance Named [Char] where
-  name = error "Name.name: used a String as a name"
-  baseName = BS.pack
-
-instance Named Name where
-  name = id
-
-data a ::: b = !a ::: !b deriving (Show, Typeable)
-
-lhs :: (a ::: b) -> a
-lhs (x ::: _) = x
-
-rhs :: (a ::: b) -> b
-rhs (_ ::: y) = y
-
-instance Named a => Eq (a ::: b) where s == t = name s == name t
-instance Named a => Ord (a ::: b) where compare = comparing name
-instance Named a => Hashable (a ::: b) where hashWithSalt s = hashWithSalt s . name
-
-instance Named a => Named (a ::: b) where
-  name (a ::: b) = name a
-
-newtype NameM a =
-  NameM { unNameM :: State Int64 a }
-    deriving (Functor, Applicative, Monad)
-
-newName :: Named a => a -> NameM Name
-newName x = NameM $ do
-  idx <- get
-  let idx'= idx+1
-  when (idx' < 0) $ error "Name.newName: too many names"
-  put $! idx'
-  return $! Name idx' (baseName x)
-
-data Closed a =
-  Closed {
-    maxIndex :: {-# UNPACK #-} !Int64,
-    open :: !a } deriving Typeable
-
-unsafeClose = Closed
-
-instance Functor Closed where
-  fmap f (Closed m x) = Closed m (f x)
-
-closed0 :: Closed ()
-nameO, nameI :: Name
-
-closed0 = close_ stdNames (return ())
-[nameO, nameI] = open stdNames
-
-stdNames :: Closed [Name]
-stdNames = close (Closed 0 ["$o", "$i"]) (mapM newName)
-
-close :: Closed a -> (a -> NameM b) -> Closed b
-close Closed{ maxIndex = maxIndex, open = open } f =
-  let (open', maxIndex') = runState (unNameM (f open)) maxIndex
-  in Closed{ maxIndex = maxIndex', open = open' }
-
-close_ :: Closed a -> NameM b -> Closed b
-close_ x m = close x (const m)
-
-closedIO :: Closed (IO a) -> IO (Closed a)
-closedIO Closed { maxIndex = maxIndex, open = open } = do
-  open' <- open
-  return Closed { maxIndex = maxIndex, open = open' }
-
-supply :: (Closed () -> Closed a) -> NameM a
-supply f = NameM $ do
-  idx <- get
-  let res = f (Closed idx ())
-  put (maxIndex res)
-  return (open res)
-
-uniquify :: [Name] -> (Name -> BS.ByteString)
-uniquify xs = f
-  -- Note to self: nameO should always be mapped to "$o".
-  -- Therefore we make sure that smaller names have priority
-  -- over bigger names here.
-  where
-    baseMap =
-      -- Assign numbers to each baseName
-      fmap (\xs -> Map.fromList (zip (usort xs) [0 :: Int ..])) .
-      -- Partition by baseName
-      foldl' (\m x -> Map.insertWith (++) (base x) [x] m) Map.empty $
-      xs
-    f x = combine (base x) b
-      where
-        b = Map.findWithDefault (error $ "Name.uniquify: name " ++ show x ++ " not found") x
-            (Map.findWithDefault (error $ "Name.uniquify: name " ++ show x ++ " not found") (baseName x) baseMap)
-    combine s 0 = s
-    combine s n = disambiguate (BS.append s (BS.pack (show n)))
-    disambiguate s
-      | not (Map.member s baseMap) = s
-      | otherwise =
-        -- Odd situation: we have e.g. a name with baseName "f1",
-        -- and two names with baseName "f", which would normally
-        -- become "f" and "f1", but the "f1" conflicts.
-        -- Try appending some suffix.
-        disambiguate (BS.snoc s '_')
diff --git a/Jukebox/NameMap.hs b/Jukebox/NameMap.hs
deleted file mode 100644
--- a/Jukebox/NameMap.hs
+++ /dev/null
@@ -1,46 +0,0 @@
-module Jukebox.NameMap(NameMap, lookup, lookup_, insert, member, delete, (!), fromList, toList, singleton) where
-
-import Prelude hiding (lookup)
-import Jukebox.Name
-import Jukebox.Map(Map)
-import qualified Jukebox.Map as Map
-import Data.Int
-import qualified Jukebox.Seq as S
-
-type NameMap a = Map Int64 a
-
-lookup :: Name -> NameMap a -> Maybe a
-lookup x m = Map.lookup (uniqueId x) m
-
-lookup_ :: Named a => a -> NameMap b -> b
-lookup_ x m =
-  case lookup (name x) m of
-    Nothing -> error "NameMap.lookup_: key not found"
-    Just y -> y
-
-insert :: Named a => a -> NameMap a -> NameMap a
-insert x m = Map.insert (uniqueId (name x)) x m
-
-member :: Named a => a -> NameMap a -> Bool
-member x m = keyMember (name x) m
-
-keyMember :: Name -> NameMap a -> Bool
-keyMember x m = Map.member (uniqueId x) m
-
-delete :: Named a => a -> NameMap a -> NameMap a
-delete x m = deleteKey (name x) m
-
-deleteKey :: Name -> NameMap a -> NameMap a
-deleteKey x m = Map.delete (uniqueId x) m
-
-(!) :: NameMap a -> Name -> a
-m ! x = m Map.! uniqueId (name x)
-
-fromList :: (S.List f, Named a) => f a -> NameMap a
-fromList xs = Map.fromList [ (uniqueId (name x), x) | x <- S.toList xs ]
-
-toList :: NameMap a -> [a]
-toList = Map.elems
-
-singleton :: Named a => a -> NameMap a
-singleton x = insert x Map.empty
diff --git a/Jukebox/Options.hs b/Jukebox/Options.hs
deleted file mode 100644
--- a/Jukebox/Options.hs
+++ /dev/null
@@ -1,358 +0,0 @@
-{-# LANGUAGE FlexibleContexts #-}
-module Jukebox.Options where
-
-import Control.Arrow((***))
-import Control.Applicative
-import Control.Monad(mplus)
-import Data.Char
-import Data.List
-import Data.Monoid
-import System.Environment
-import System.Exit
-import System.IO
-
-----------------------------------------------------------------------
--- A parser of some kind annotated with a help text of some kind
-data Annotated d p a = Annotated
-  { descr :: d,
-    parser :: p a }
-
-instance Functor p => Functor (Annotated d p) where
-  fmap f (Annotated d x) = Annotated d (fmap f x)
-
-instance (Monoid d, Applicative p) => Applicative (Annotated d p) where
-  pure = Annotated mempty . pure
-  Annotated d f <*> Annotated d' x =
-    Annotated (d `mappend` d') (f <*> x)
-
-instance (Monoid d, Monoid (p a)) => Monoid (Annotated d p a) where
-  mempty = Annotated mempty mempty
-  Annotated d p `mappend` Annotated d' p' =
-    Annotated (d `mappend` d') (p `mappend` p')
-
-----------------------------------------------------------------------
--- Parsing of single arguments (e.g. integers)
--- and single flags (e.g. --verbosity 3).
-
-type ArgParser = Annotated ArgDesc SeqParser
-type ArgDesc = String -- description, e.g. "<number>"
-
--- Called SeqParser because <*> is sequential composition.
-data SeqParser a = SeqParser
-  { args :: Int, -- How many arguments will be consumed
-    consume :: [String] -> Either Error a }
-
-instance Functor SeqParser where
-  fmap f (SeqParser a c) = SeqParser a (fmap f . c)
-
-instance Applicative SeqParser where
-  pure = SeqParser 0 . const . pure
-  SeqParser a c <*> SeqParser a' c' = SeqParser (a + a') f
-    where f xs = c xs <*> c' (drop a xs)
-
-arg :: ArgDesc -> String -> (String -> Maybe a) -> ArgParser a
-arg desc err f = Annotated desc (SeqParser 1 c)
-  where c [] = Left (Mistake err)
-        c (x:_) | "--" `isPrefixOf` x = Left (Mistake err)
-        c (x:_) =
-          case f x of
-            Nothing -> Left (Mistake err)
-            Just ok -> Right ok
-
-argNum :: (Read a, Num a) => ArgParser a
-argNum = arg "<num>" "expected a number" f
-  where f x =
-          case reads x of
-            [(y, "")] -> Just y
-            _ -> Nothing
-
-argFile :: ArgParser FilePath
-argFile = arg "<file>" "expected a file" Just
-
-argFiles :: ArgParser [FilePath]
-argFiles = arg "<files>" "expected a list of files" $ \x ->
-  Just $ elts $ x ++ ","
-  where
-    elts [] = []
-    elts s  = w:elts r
-      where
-        w = takeWhile (/= ',') s
-        r = tail (dropWhile (/= ',') s)
-
-argName :: ArgParser FilePath
-argName = arg "<name>" "expected a name" Just
-
-argNums :: ArgParser [Int]
-argNums = arg "<nums>" "expected a number list" $ \x ->
-  nums . groupBy (\x y -> isDigit x == isDigit y) $ x ++ ","
-  where
-    nums []                = Just []
-    nums (n:",":ns)        = (read n :) `fmap` nums ns
-    nums (n:"..":m:",":ns) = ([read n .. read m] ++) `fmap` nums ns
-    nums _                 = Nothing
-
-argOption :: [String] -> ArgParser String
-argOption as = arg ("<" ++ concat (intersperse " | " as) ++ ">") "expected an argument" elts
-  where
-    elts x | x `elem` as = Just x
-           | otherwise   = Nothing
-
-argList :: [String] -> ArgParser [String]
-argList as = arg ("<" ++ concat (intersperse " | " as) ++ ">*") "expected an argument" $ \x ->
-  elts $ x ++ ","
-  where
-    elts []              = Just []
-    elts s | w `elem` as = (w:) `fmap` elts r
-      where
-        w = takeWhile (/= ',') s
-        r = tail (dropWhile (/= ',') s)
-    
-    elts _ = Nothing
-
--- A parser that always fails but produces an error message (useful for --help etc.)
-argUsage :: ExitCode -> [String] -> ArgParser a
-argUsage code err = Annotated [] (SeqParser 0 (const (Left (Usage code err))))
-
-----------------------------------------------------------------------
--- Parsing of whole command lines.
-
-type OptionParser = Annotated [Flag] ParParser
-
--- Called ParParser because <*> is parallel composition.
--- In other words, in f <*> x, f and x both see the whole command line.
--- We want this when parsing command lines because
--- it doesn't matter what order we write the options in.
-data ParParser a = ParParser
-  { val :: IO a, -- impure so we can put system information in our options records
-    peek :: [String] -> ParseResult a }
-
-data ParseResult a
-    -- Yes n x: consumed n arguments, continue parsing with x
-  = Yes Int (ParParser a)
-    -- No x: didn't understand this flag, continue parsing with x
-  | No (ParParser a)
-    -- Error
-  | Error Error
-
-data Error =
-    Mistake String
-  | Usage ExitCode [String]
-
-instance Functor ParParser where
-  fmap f x = pure f <*> x
-
-instance Applicative ParParser where
-  pure x = ParParser (return x) (const (pure x))
-  ParParser v p <*> ParParser v' p' =
-    ParParser (v <*> v') (\xs -> p xs <*> p' xs)
-
-instance Functor ParseResult where
-  fmap f x = pure f <*> x
-
-instance Applicative ParseResult where
-  pure = No . pure
-  Yes n r <*> Yes n' r'
-    | n == n' = Yes n (r <*> r')
-    | otherwise = error "Options.ParseResult: inconsistent number of arguments"
-  Error s <*> _ = Error s
-  _ <*> Error s = Error s
-  Yes n r <*> No x = Yes n (r <*> x)
-  No x <*> Yes n r = Yes n (x <*> r)
-  No f <*> No x = No (f <*> x)
-
-runPar :: ParParser a -> [String] -> Either Error (IO a)
-runPar p [] = Right (val p)
-runPar p xs@(x:_) =
-  case peek p xs of
-    Yes n p' -> runPar p' (drop n xs)
-    No _ -> Left (Mistake ("Didn't recognise option " ++ x))
-    Error err -> Left err
-
-awaitP :: (String -> Bool) -> a -> (String -> [String] -> ParseResult a) -> ParParser a
-awaitP p def par = ParParser (return def) f
-  where f (x:xs) | p x =
-          case par x xs of
-            Yes n r -> Yes (n+1) r
-            No _ ->
-              error "Options.await: got No"
-            Error err -> Error err
-        f _ = No (awaitP p def par)
-
-await :: String -> a -> ([String] -> ParseResult a) -> ParParser a
-await flag def f = awaitP (\x -> "--" ++ flag == x) def (const f)
-
-data Flag = Flag
-  { flagName :: String,
-    flagGroup :: String,
-    flagHelp :: [String],
-    flagArgs :: String } deriving (Eq, Show)
-
--- From a flag name and and argument parser, produce an OptionParser.
-flag :: String -> [String] -> a -> ArgParser a -> OptionParser a
-flag name help def (Annotated desc (SeqParser args f)) =
-  Annotated [desc'] (await name def g)
-  where desc' = Flag name "Common options" help desc
-        g xs =
-          case f xs of
-            Left (Mistake err) -> Error (Mistake ("Error in option --" ++ name ++ ": " ++ err))
-            Left (Usage code err) -> Error (Usage code err)
-            Right y -> Yes args (pure y <* noFlag)
-        -- Give an error if the flag is repeated.
-        noFlag =
-          await name ()
-            (const (Error (Mistake ("Option --" ++ name ++ " occurred twice"))))
-
-manyFlags :: String -> [String] -> ArgParser a -> OptionParser [a]
-manyFlags name help (Annotated desc (SeqParser args f)) =
-  fmap reverse (Annotated [desc'] (go []))
-  where desc' = Flag name "Common options" help desc
-        go xs = await name xs (g xs)
-        g xs ys =
-          case f ys of
-            Left (Mistake err) -> Error (Mistake ("Error in option --" ++ name ++ ": " ++ err))
-            Left (Usage code err) -> Error (Usage code err)
-            Right x -> Yes args (go (x:xs))
-
--- Read filenames from the command line.
-filenames :: OptionParser [String]
-filenames = Annotated [] (from [])
-  where from xs = awaitP p xs (f xs)
-        p x = not ("--" `isPrefixOf` x)
-        f xs y ys = Yes 0 (from (xs ++ [y]))
-
--- Take a value from the environment.
-io :: IO a -> OptionParser a
-io m = Annotated [] p
-  where p = ParParser m (const (No p))
-
--- A boolean flag.
-bool :: String -> [String] -> OptionParser Bool
-bool name help = flag name help False (pure True)
-
-inGroup :: String -> OptionParser a -> OptionParser a
-inGroup x (Annotated fls f) = Annotated [fl{ flagGroup = x } | fl <- fls] f
-
-----------------------------------------------------------------------
--- Selecting a particular tool.
-
-type ToolParser = Annotated [Tool] PrefixParser
-data Tool = Tool
-  { toolProgName :: String,
-    toolName :: String,
-    toolVersion :: String,
-    toolHelp :: String }
-
-newtype PrefixParser a = PrefixParser (String -> Maybe (Tool, ParParser a))
-
-instance Functor PrefixParser where
-  fmap f (PrefixParser g) = PrefixParser (fmap (id *** fmap f) . g)
-
-instance Monoid (PrefixParser a) where
-  mempty = PrefixParser (const Nothing)
-  PrefixParser f `mappend` PrefixParser g =
-    PrefixParser (\xs -> f xs `mplus` g xs)
-
-runPref :: PrefixParser a -> [String] -> Either Error (IO a)
-runPref _ [] = Left (Mistake "Expected a tool name")
-runPref (PrefixParser f) (x:xs) =
-  case f x of
-    Nothing -> Left (Mistake ("No such tool " ++ x))
-    Just (t, p) ->
-      case runPar p xs of
-        Left (Mistake x) -> Left (Usage (ExitFailure 1) (argError t x))
-        Left (Usage code x) -> Left (Usage code x)
-        Right x -> Right x
-
-tool :: Tool -> OptionParser a -> ToolParser a
-tool t p =
-  Annotated [t] (PrefixParser f)
-  where f x | x == toolProgName t = Just (t, parser p')
-        f _ = Nothing
-        p' = p <* versionParser <* helpParser
-        helpParser = flag "help" ["Show this help text."] () (argUsage ExitSuccess (help t p'))
-        versionParser = flag "version" ["Print the version number."] () (argUsage ExitSuccess [greeting t])
-
--- Use the program name as a tool name if possible.
-getEffectiveArgs :: ToolParser a -> IO [String]
-getEffectiveArgs (Annotated tools _) = do
-  progName <-
-    case tools of
-      [tool] -> return (toolProgName tool)
-      _ -> getProgName
-  args <- getArgs
-  if progName `elem` map toolProgName tools
-    then return (progName:args)
-    else return args
-
-parseCommandLine :: Tool -> ToolParser a -> IO a
-parseCommandLine t p = do
-  let p' =
-        case p of
-          Annotated [_] _ -> p
-          _ -> versionTool t `mappend` helpTool t p `mappend` p
-  args <- getEffectiveArgs p'
-  case runPref (parser p') args of
-    Left (Mistake err) -> printHelp (ExitFailure 1) (argError t err)
-    Left (Usage code err) -> printHelp code err
-    Right x -> x
-
-----------------------------------------------------------------------
--- Help screens.
-
-printHelp :: ExitCode -> [String] -> IO a
-printHelp code xs = do
-  mapM_ (hPutStrLn stderr ) xs
-  exitWith code
-
-argError :: Tool -> String -> [String]
-argError t err = [
-  greeting t,
-  err ++ ". Try --help."
-  ]
-
-usageTool :: Tool -> String -> [String] -> String -> ToolParser a
-usageTool t0 flag msg bit = tool (Tool flag' flag' flag' "0") p
-  where p = Annotated [] (ParParser (printHelp ExitSuccess msg)
-                                    (const (Error (Usage (ExitFailure 1) msg'))))
-        flag' = "--" ++ flag
-        msg' = [
-          greeting t0,
-          "Didn't expect any arguments after " ++ flag' ++ ".",
-          "Try " ++ toolProgName t0 ++ " <toolname> " ++ flag' ++ " if you want " ++ bit ++ " a particular tool."
-          ]
-
-versionTool :: Tool -> ToolParser a
-versionTool t0 = usageTool t0 "version" [greeting t0] "the version of"
-
-helpTool :: Tool -> ToolParser a -> ToolParser a
-helpTool t0 p = usageTool t0 "help" help "help for"
-  where help = concat [
-          [greeting t0],
-          usage t0 "<toolname> ",
-          ["<toolname> can be any of the following:"],
-          concat [ justify (toolProgName t) [toolHelp t] | t <- descr p ],
-          ["", "Use " ++ toolProgName t0 ++ " <toolname> --help for help on a particular tool."]
-          ]
-
-help :: Tool -> OptionParser a -> [String]
-help t p = concat [
-  [greeting t],
-  usage t "",
-  ["<option> can be any of the following:"],
-  concat [ justify ("--" ++ flagName f ++ " " ++ flagArgs f) (flagHelp f) | f <- nub (descr p) ]
-  ]
-
-greeting :: Tool -> String
-greeting t = toolName t ++ ", version " ++ toolVersion t ++ "."
-
-usage :: Tool -> String -> [String]
-usage t opts = [
-  "Usage: " ++ toolProgName t ++ " " ++ opts ++ "<option>* <file>*",
-  toolHelp t ++ ".",
-  "",
-  "<file> should be in TPTP format.",
-  ""
-  ]
-
-justify :: String -> [String] -> [String]
-justify name help = ["", "  " ++ name] ++ map ("    " ++) help
diff --git a/Jukebox/ProgressBar.hs b/Jukebox/ProgressBar.hs
deleted file mode 100644
--- a/Jukebox/ProgressBar.hs
+++ /dev/null
@@ -1,67 +0,0 @@
-module Jukebox.ProgressBar(ProgressBar(..), tickOnRead, withProgressBar) where
-
-import System.IO
-import Data.IORef
-import Data.Word
-import qualified Data.ByteString.Lazy as BSL
---import Data.ByteString.Lazy.Progress
-import Control.Exception
-import Control.Monad
-import Prelude hiding (last)
-
-data ProgressBar = ProgressBar { 
-  tick :: IO (),
-  enter :: String -> IO (),
-  leave :: IO ()
-  }
-
-data State = State {
-  position :: Int,
-  enabled :: Bool,
-  level :: Int,
-  last :: Last
-  }
-             
--- What happened last.
-data Last = Tick | Enter | Leave
-
-tickOnRead :: ProgressBar -> BSL.ByteString -> IO BSL.ByteString
-tickOnRead p s = do
-  let chunkSize = 1000000 :: Word64
-  nextRef <- newIORef chunkSize
-  let f _ index = do
-        next <- readIORef nextRef
-        when (next <= index) $ do
-          tick p
-          writeIORef nextRef (next + chunkSize)
-  -- trackProgress f s
-  return s
-
-withProgressBar :: (ProgressBar -> IO a) -> IO a
-withProgressBar f = do
-  state <- newIORef State { position = 0, enabled = True, level = 0, last = Enter }
-  let spinny 0 = ".-\08"
-      spinny 1 = "\\\08"
-      spinny 2 = "|\08"
-      spinny 3 = "/\08"
-      put s = hPutStr stderr s >> hFlush stderr
-      tick = do
-        s <- readIORef state
-        pos <-
-          case last s of
-            Tick -> return (position s)
-            Enter -> return 0
-            Leave -> put " " >> return 0
-        put (spinny pos)
-        writeIORef state s{ position = (pos+1) `mod` 4, last = Tick }
-      enter msg = do
-        s <- readIORef state
-        when (level s /= 0) (put " (")
-        put (msg ++ "...")
-        writeIORef state s{ last = Enter, level = level s + 1 }
-      leave = do
-        s <- readIORef state
-        when (level s /= 1) (put ")")
-        writeIORef state s{last = Leave, level = level s - 1 }
-  f ProgressBar { tick = tick, enter = enter, leave = leave }
-    `finally` put " \n"
diff --git a/Jukebox/Provers/E.hs b/Jukebox/Provers/E.hs
deleted file mode 100644
--- a/Jukebox/Provers/E.hs
+++ /dev/null
@@ -1,113 +0,0 @@
-{-# LANGUAGE GADTs #-}
-module Jukebox.Provers.E where
-
-import Jukebox.Form hiding (tag, Or)
-import Jukebox.Name
-import Jukebox.Options
-import Control.Applicative hiding (Const)
-import Control.Monad
-import Jukebox.Utils
-import Jukebox.TPTP.Parsec
-import Jukebox.TPTP.ClauseParser hiding (newFunction, Term)
-import Jukebox.TPTP.Print
-import Jukebox.TPTP.Lexer hiding (Normal, keyword, Axiom, name, Var)
-import Text.PrettyPrint.HughesPJ hiding (parens)
-import Data.Maybe
-import qualified Data.ByteString.Char8 as BS
-import qualified Data.ByteString.Lazy.Char8 as BSL
-import qualified Jukebox.Seq as S
-import qualified Jukebox.Map as Map
-import Jukebox.Map(Map)
-import Data.Hashable
-import System.Exit
-
-data EFlags = EFlags {
-  eprover :: String,
-  timeout :: Maybe Int,
-  memory :: Maybe Int
-  }
-
-eflags =
-  inGroup "E prover options" $
-  EFlags <$>
-    flag "eprover"
-      ["Path to the E theorem prover.",
-       "Default: eprover"]
-      "eprover"
-      argFile <*>
-    flag "timeout"
-      ["Timeout for E, in seconds.",
-       "Default: (off)"]
-      Nothing
-      (fmap Just argNum) <*>
-    flag "memory"
-      ["Memory limit for E, in megabytes.",
-       "Default: (off)"]
-      Nothing
-      (fmap Just argNum)
-
--- Work around bug in E answer coding.
-mangleAnswer :: Symbolic a => a -> NameM a
-mangleAnswer t =
-  case typeOf t of
-    Term -> term t
-    _ -> recursivelyM mangleAnswer t
-  where term (f :@: [t]) | stringBaseName f == "$answer" = do
-          wrap <- newFunction "answer" [typ t] (head (funArgs f))
-          return (f :@: [wrap :@: [t]])
-        term t = recursivelyM mangleAnswer t
-
-runE :: (Pretty a, Symbolic a) => EFlags -> Problem a -> IO (Either Answer [Term])
-runE flags prob
-  | not (isFof (open prob)) = error "runE: E doesn't support many-typed problems"
-  | otherwise = do
-    (code, str) <- popen (eprover flags) eflags
-                   (BS.pack (render (prettyProblem "fof" Normal (close prob mangleAnswer))))
-    --case code of
-    --  ExitFailure code -> error $ "runE: E failed with exit code " ++ show code ++ ":\n" ++ BS.unpack str
-    return (extractAnswer (open prob) (BS.unpack str))
-  where eflags = [ "--soft-cpu-limit=" ++ show n | Just n <- [timeout flags] ] ++
-                 ["--memory-limit=" ++ show n | Just n <- [memory flags] ] ++
-                 ["--tstp-in", "--tstp-out", "-tAuto", "-xAuto"] ++
-                 ["-l", "0"]
-
-extractAnswer :: Symbolic a => a -> String -> Either Answer [Term]
-extractAnswer prob str = fromMaybe (Left status) (fmap Right answer)
-  where env = uniquify (S.unique (names prob))
-        varMap = Map.fromList [(env (name x), x) | x <- vars prob]
-        funMap = Map.fromList [(env (name x), x) | x <- functions prob]
-        result = lines str
-        status = head $
-          [Satisfiable | "# SZS status Satisfiable" <- result] ++
-          [Satisfiable | "# SZS status CounterSatisfiable" <- result] ++
-          [Unsatisfiable | "# SZS status Unsatisfiable" <- result] ++
-          [Unsatisfiable | "# SZS status Theorem" <- result] ++
-          [NoAnswer Timeout | "# SZS status ResourceOut" <- result] ++
-          [NoAnswer Timeout | "# SZS status Timeout" <- result] ++
-          [NoAnswer Timeout | "# SZS status MemyOut" <- result] ++
-          [NoAnswer GaveUp]
-        answer = listToMaybe $
-          [ parse xs
-          | line <- result
-          , let prefix = "# SZS answers Tuple ["
-                suffix = "|_]"
-                (prefix', mid) = splitAt (length prefix) line
-                (xs, suffix') = splitAt (length mid - length suffix) mid
-          , prefix == prefix'
-          , suffix == suffix' ]
-        parse xs =
-          let toks = scan (BSL.pack xs)
-          in case run_ parser (UserState initialState toks) of
-            Ok _ ts -> ts
-            _ -> error "runE: couldn't parse result from E"
-        parser =
-          parens (bracks term `sepBy1` punct Or)
-          <|> fmap (:[]) (bracks term)
-        term =
-          fmap (Var . lookup varMap) variable <|>
-          liftM2 (:@:) (fmap (lookup funMap) atom) terms
-        terms =
-          bracks (term `sepBy1` punct Comma)
-          <|> return []
-        lookup :: (Ord a, Hashable a) => Map BS.ByteString a -> BS.ByteString -> a
-        lookup m x = Map.findWithDefault (error "runE: result from E mentions free names") x m
diff --git a/Jukebox/Provers/SPASS.hs b/Jukebox/Provers/SPASS.hs
deleted file mode 100644
--- a/Jukebox/Provers/SPASS.hs
+++ /dev/null
@@ -1,67 +0,0 @@
-{-# LANGUAGE GADTs #-}
-module Jukebox.Provers.SPASS where
-
-import Jukebox.Form hiding (tag, Or)
-import Jukebox.Name
-import Jukebox.Options
-import Control.Applicative hiding (Const)
-import Control.Monad
-import Jukebox.Utils
-import Jukebox.TPTP.Parsec
-import Jukebox.TPTP.ClauseParser hiding (newFunction, Term)
-import Jukebox.TPTP.Print
-import Jukebox.TPTP.Lexer hiding (Normal, keyword, Axiom, name, Var)
-import Text.PrettyPrint.HughesPJ hiding (parens)
-import Data.Maybe
-import qualified Data.ByteString.Char8 as BS
-import qualified Data.ByteString.Lazy.Char8 as BSL
-import qualified Jukebox.Seq as S
-import qualified Jukebox.Map as Map
-import Jukebox.Map(Map)
-import Data.Hashable
-import System.Exit
-
-data SPASSFlags =
-  SPASSFlags {
-    spass   :: String,
-    timeout :: Maybe Int,
-    sos     :: Bool }
-
-spassFlags =
-  inGroup "SPASS prover options" $
-  SPASSFlags <$>
-    flag "spass"
-      ["Path to SPASS.",
-       "Default: SPASS"]
-      "SPASS"
-      argFile <*>
-    flag "timeout"
-      ["Timeout in seconds.",
-       "Default: (none)"]
-      Nothing
-      (fmap Just argNum) <*>
-    flag "sos"
-      ["Use set-of-support strategy.",
-       "Default: false"]
-      False
-      (pure True)
-
-runSPASS :: (Pretty a, Symbolic a) => SPASSFlags -> Problem a -> IO Answer
-runSPASS flags prob
-  | not (isFof (open prob)) = error "runSPASS: SPASS doesn't support many-typed problems"
-  | otherwise = do
-    (code, str) <- popen (spass flags) spassFlags
-                   (BS.pack (render (prettyProblem "cnf" Normal prob)))
-    return (extractAnswer (BS.unpack str))
-  where
-    spassFlags =
-      ["-TimeLimit=" ++ show n | Just n <- [timeout flags] ] ++
-      ["-SOS" | sos flags] ++
-      ["-TPTP", "-Stdin"]
-
-extractAnswer :: String -> Answer
-extractAnswer result =
-  head $
-    [ Unsatisfiable    | "SPASS beiseite: Proof found." <- lines result ] ++
-    [ Satisfiable      | "SPASS beiseite: Completion found." <- lines result ] ++
-    [ NoAnswer Timeout ]
diff --git a/Jukebox/Sat.hs b/Jukebox/Sat.hs
deleted file mode 100644
--- a/Jukebox/Sat.hs
+++ /dev/null
@@ -1,70 +0,0 @@
-module Jukebox.Sat
-  ( Solver
-  , newSolver
-  , deleteSolver
-  , Lit, neg
-  , false, true
-  
-  , SatSolver(..)
-  , newLit
-  , addClause
-  , solve
-  , conflict
-  , modelValue
-  , value
-  )
- where
-
---------------------------------------------------------------------------------
-
-import MiniSat
-  ( Solver
-  , deleteSolver
-  , Lit(..)
-  , neg
-  )
-
-import qualified MiniSat as M
-
---------------------------------------------------------------------------------
-
-false, true :: Lit
-true  = MkLit 0
-false = neg true
-
-newSolver :: IO Solver
-newSolver =
-  do s <- M.newSolver
-     x <- M.newLit s
-     if x == false || x == true
-       then do M.addClause s [true]
-               return s
-       else do error "failed to initialize false and true!"
-
---------------------------------------------------------------------------------
-
-class SatSolver s where
-  getSolver :: s -> Solver
-
-instance SatSolver Solver where
-  getSolver s = s
-
-newLit :: SatSolver s => s -> IO Lit
-newLit s = M.newLit (getSolver s)
-
-addClause :: SatSolver s => s -> [Lit] -> IO ()
-addClause s xs = M.addClause (getSolver s) xs >> return ()
-
-solve :: SatSolver s => s -> [Lit] -> IO Bool
-solve s xs = M.solve (getSolver s) xs
-
-conflict :: SatSolver s => s -> IO [Lit]
-conflict s = M.conflict (getSolver s)
-
-modelValue :: SatSolver s => s -> Lit -> IO (Maybe Bool)
-modelValue s x = M.modelValue (getSolver s) x
-
-value :: SatSolver s => s -> Lit -> IO (Maybe Bool)
-value s x = M.value (getSolver s) x
-
---------------------------------------------------------------------------------
diff --git a/Jukebox/Sat3.hs b/Jukebox/Sat3.hs
deleted file mode 100644
--- a/Jukebox/Sat3.hs
+++ /dev/null
@@ -1,47 +0,0 @@
-module Jukebox.Sat3 where
-
-import Jukebox.Sat
-
---------------------------------------------------------------------------------
-
-data Lit3 = Lit3{ isFalse :: Lit, isTrue :: Lit }
-
-false3, true3, bottom3 :: Lit3
-false3  = Lit3 true false
-true3   = neg3 false3
-bottom3 = Lit3 false false
-
-neg3 :: Lit3 -> Lit3
-neg3 (Lit3 f t) = Lit3 t f
-
-newLit3 :: SatSolver s => s -> IO Lit3
-newLit3 s =
-  do a <- newLit s
-     b <- newLit s
-     addClause s [neg a, neg b]
-     return (Lit3 a b)
-
-newLit2 :: SatSolver s => s -> IO Lit3
-newLit2 s =
-  do a <- newLit s
-     return (Lit3 a (neg a))
-
---------------------------------------------------------------------------------
-
-modelValue3 :: SatSolver s => s -> Lit3 -> IO (Maybe Bool)
-modelValue3 s = val3 (modelValue s)
-
-value3 :: SatSolver s => s -> Lit3 -> IO (Maybe Bool)
-value3 s = val3 (value s)
-
-val3 :: (Lit -> IO (Maybe Bool)) -> Lit3 -> IO (Maybe Bool)
-val3 get (Lit3 f t) =
-  do mf <- get f
-     case mf of
-       Just True -> do return (Just False)
-       _         -> do mt <- get t
-                       case mt of
-                         Just True -> return (Just True)
-                         _         -> return Nothing
-
---------------------------------------------------------------------------------
diff --git a/Jukebox/SatEq.hs b/Jukebox/SatEq.hs
deleted file mode 100644
--- a/Jukebox/SatEq.hs
+++ /dev/null
@@ -1,85 +0,0 @@
-module Jukebox.SatEq where
-
-import Jukebox.Sat
-import Jukebox.Sat3
-import Jukebox.SatMin
-
-import Data.IORef
-import Data.Map as M
-
---------------------------------------------------------------------------------
-
-data SolverEq =
-  SolverEq
-  { satSolver :: Solver
-  , counter   :: IORef Int
-  , table     :: IORef (Map (Elt,Elt) Lit3)
-  , model     :: IORef (Maybe (Map Elt Elt))
-  }
-
-newSolverEq :: Solver -> IO SolverEq
-newSolverEq s =
-  do ctr <- newIORef 0
-     tab <- newIORef M.empty
-     mod <- newIORef Nothing
-     return SolverEq
-       { satSolver = s
-       , counter   = ctr
-       , table     = tab
-       , model     = mod
-       }
-
-instance SatSolver SolverEq where
-  getSolver = satSolver
-
-class SatSolver s => EqSolver s where
-  getSolverEq :: s -> SolverEq
-
-instance EqSolver SolverEq where
-  getSolverEq s = s
-
---------------------------------------------------------------------------------
-
-newtype Elt = Elt Int
-  deriving ( Eq, Ord )
-
-instance Show Elt where
-  show (Elt k) = "#" ++ show k
-
-newElt :: EqSolver s => s -> IO Elt
-newElt s =
-  do k <- readIORef (counter (getSolverEq s))
-     writeIORef (counter (getSolverEq s)) $! k+1
-     return (Elt k)
-
-equal :: EqSolver s => s -> Elt -> Elt -> IO Lit3
-equal s x y =
-  case x `compare` y of
-    GT -> equal s y x
-    EQ -> return true3
-    LT -> do tab <- readIORef (table (getSolverEq s))
-             case M.lookup (x,y) tab of
-               Just q ->
-                 do return q
-       
-               Nothing ->
-                 do q <- newLit3 s
-                    writeIORef (table (getSolverEq s)) (M.insert (x,y) q tab)
-                    return q
-
---------------------------------------------------------------------------------
-
-solveEq :: EqSolver s => s -> [Lit] -> IO Bool
-solveEq = undefined
-
---------------------------------------------------------------------------------
-
-modelRep :: EqSolver s => s -> Elt -> IO (Maybe Elt)
-modelRep s x =
-  do mmod <- readIORef (model (getSolverEq s))
-     return $
-       case mmod of
-         Just mp -> M.lookup x mp
-         Nothing -> Nothing
-
---------------------------------------------------------------------------------
diff --git a/Jukebox/SatMin.hs b/Jukebox/SatMin.hs
deleted file mode 100644
--- a/Jukebox/SatMin.hs
+++ /dev/null
@@ -1,29 +0,0 @@
-module Jukebox.SatMin where
-
-import Jukebox.Sat
-
-solveLocalMin :: SatSolver s => s -> [Lit] -> [Lit] -> IO Bool
-solveLocalMin s as ms =
-  do b <- solve s as
-     if b then do l <- newLit s -- used as a local assumption for this minimization
-                  localMin s as l ms
-                  addClause s [neg l]
-                  return True
-          else do return False
-
-localMin :: SatSolver s => s -> [Lit] -> Lit -> [Lit] -> IO ()
-localMin s as l ms =
-  do -- find out the current values of the m's
-     bs <- sequence [ modelValue s m | m <- ms ]
-  
-     -- assert that all false m's should stay false
-     sequence_ [ addClause s [neg l, neg m] | (m,b) <- ms `zip` bs, b /= Just True ]
-     
-     -- assert that at least one true m should become false also
-     let ms1 = [ m | (m,Just True)  <- ms `zip` bs ]
-     addClause s (neg l : [ neg m | m <- ms1 ])
-     
-     -- is there still a solution?
-     b <- solve s (l:as)
-     if b then localMin s as l ms1
-          else return ()
diff --git a/Jukebox/Seq.hs b/Jukebox/Seq.hs
deleted file mode 100644
--- a/Jukebox/Seq.hs
+++ /dev/null
@@ -1,109 +0,0 @@
--- Strict lists with efficient append.
-module Jukebox.Seq where
-
-import Prelude hiding (concat, concatMap, length, mapM, mapM_)
-import Control.Monad hiding (mapM, mapM_)
-import Data.Hashable
-import qualified Data.HashSet as Set
-import Data.Monoid
-import Control.Applicative
-
-data Seq a = Append (Seq a) (Seq a) | Unit a | Nil
-
-class List f where
-  fromList :: f a -> Seq a
-  toList :: f a -> [a]
-
-instance List [] where
-  fromList = foldr cons Nil
-  toList = id
-
-instance List Seq where
-  fromList = id
-  toList x = go [x]
-    -- (if you squint here you can see difference lists...)
-    where go (Nil:left) = go left
-          go (Unit x:left) = x:go left
-          go (Append x y:left) = go (x:y:left)
-          go [] = []
-
-appendA :: Seq a -> Seq a -> Seq a
-appendA Nil xs = xs
-appendA xs Nil = xs
-appendA xs ys = Append xs ys
-
-instance Show a => Show (Seq a) where
-  show = show . toList
-
-cons :: a -> Seq a -> Seq a
-cons x xs = Unit x `appendA` xs
-
-snoc :: Seq a -> a -> Seq a
-snoc xs x = xs `appendA` Unit x
-
-append :: (List f, List g) => f a -> g a -> Seq a
-append xs ys = fromList xs `appendA` fromList ys
-
-instance Functor Seq where
-  fmap f (Append x y) = Append (fmap f x) (fmap f y)
-  fmap f (Unit x) = Unit (f x)
-  fmap f Nil = Nil
-
-instance Applicative Seq where
-  pure = return
-  (<*>) = liftM2 ($)
-
-instance Monad Seq where
-  return = Unit
-  x >>= f = concatMapA f x
-  fail _ = Nil
-
-instance Alternative Seq where
-  empty = mzero
-  (<|>) = mplus
-
-instance MonadPlus Seq where
-  mzero = Nil
-  mplus = append
-
-instance Monoid (Seq a) where
-  mempty = Nil
-  mappend = append
-
-concat :: (List f, List g) => f (g a) -> Seq a
-concat = concatMap id
-
-concatMap :: (List f, List g) => (a -> g b) -> f a -> Seq b
-concatMap f xs = concatMapA (fromList . f) (fromList xs)
-
-concatMapA :: (a -> Seq b) -> Seq a -> Seq b
-concatMapA f = aux
-  where aux (Append x y) = aux x `appendA` aux y
-        aux (Unit x) = f x
-        aux Nil = Nil
-
-fold :: (b -> b -> b) -> (a -> b) -> b -> Seq a -> b
-fold app u n (Append x y) = app (fold app u n x) (fold app u n y)
-fold app u n (Unit x) = u x
-fold app u n Nil = n
-
-unique :: (Ord a, Hashable a, List f) => f a -> [a]
-unique = Set.toList . Set.fromList . toList . fromList
-
-length :: Seq a -> Int
-length Nil = 0
-length (Unit _) = 1
-length (Append x y) = length x + length y
-
-mapM :: Monad m => (a -> m b) -> Seq a -> m (Seq b)
-mapM f Nil = return Nil
-mapM f (Unit x) = liftM Unit (f x)
-mapM f (Append x y) = liftM2 Append (mapM f x) (mapM f y)
-
-mapM_ :: Monad m => (a -> m ()) -> Seq a -> m ()
-mapM_ f Nil = return ()
-mapM_ f (Unit x) = f x
-mapM_ f (Append x y) = mapM_ f x >> mapM_ f y
-
-sequence :: Monad m => Seq (m a) -> m (Seq a)
-sequence = mapM id
diff --git a/Jukebox/TPTP/ClauseParser.hs b/Jukebox/TPTP/ClauseParser.hs
deleted file mode 100644
--- a/Jukebox/TPTP/ClauseParser.hs
+++ /dev/null
@@ -1,481 +0,0 @@
--- Parse and typecheck TPTP clauses, stopping at include-clauses.
-
-{-# LANGUAGE BangPatterns, MultiParamTypeClasses, ImplicitParams, FlexibleInstances, TypeOperators, TypeFamilies #-}
-module Jukebox.TPTP.ClauseParser where
-
-import Jukebox.TPTP.Parsec
-import Control.Applicative
-import Control.Monad
-import qualified Data.ByteString.Lazy.Char8 as BSL
-import qualified Data.ByteString.Char8 as BS
-import qualified Jukebox.Map as Map
-import Jukebox.Map(Map)
-import qualified Jukebox.Seq as S
-import Jukebox.Seq(Seq)
-import Data.List
-import Jukebox.TPTP.Print
-import Jukebox.Name hiding (name)
-import qualified Jukebox.NameMap as NameMap
-
-import Jukebox.TPTP.Lexer hiding
-  (Pos, Error, Include, Var, Type, Not, ForAll,
-   Exists, And, Or, Type, Apply, Implies, Follows, Xor, Nand, Nor,
-   keyword, defined, kind)
-import qualified Jukebox.TPTP.Lexer as L
-import qualified Jukebox.Form as Form
-import Jukebox.Form hiding (tag, kind, Axiom, Conjecture, Question, newFunction, TypeOf(..))
-import qualified Jukebox.Name as Name
-
--- The parser monad
-
-data ParseState =
-  MkState ![Input Form]                           -- problem being constructed, inputs are in reverse order
-          !(Map BS.ByteString Type)               -- types
-          !(Map BS.ByteString (Name ::: FunType)) -- functions
-          !(Map BS.ByteString (Name ::: Type))    -- free variables in CNF clause
-          Type                                    -- the $i type
-          !(Closed ())                            -- name generation
-type Parser = Parsec ParsecState
-type ParsecState = UserState ParseState TokenStream
-
--- An include-clause.
-data IncludeStatement = Include BS.ByteString (Maybe [Tag]) deriving Show
-
--- The initial parser state.
-initialState :: ParseState
-initialState = MkState [] (Map.insert (BS.pack "$i") typeI Map.empty) Map.empty Map.empty typeI closed0
-  where typeI = Type nameI Infinite Infinite
-
-instance Stream TokenStream Token where
-  primToken (At _ (Cons Eof _)) ok err fatal = err
-  primToken (At _ (Cons L.Error _)) ok err fatal = fatal "Lexical error"
-  primToken (At _ (Cons t ts)) ok err fatal = ok ts t
-  type Position TokenStream = TokenStream
-  position = id
-
--- Wee function for testing.
-testParser :: Parser a -> String -> Either [String] a
-testParser p s = snd (run (const []) p (UserState initialState (scan (BSL.pack s))))
-
-getProblem :: Parser [Input Form]
-getProblem = do
-  MkState p _ _ _ _ _ <- getState
-  return (reverse p)
-
--- Primitive parsers.
-
-{-# INLINE keyword' #-}
-keyword' p = satisfy p'
-  where p' Atom { L.keyword = k } = p k
-        p' _ = False
-{-# INLINE keyword #-}
-keyword k = keyword' (== k) <?> "'" ++ show k ++ "'"
-{-# INLINE punct' #-}
-punct' p = satisfy p'
-  where p' Punct { L.kind = k } = p k
-        p' _ = False
-{-# INLINE punct #-}
-punct k = punct' (== k) <?> "'" ++ show k ++ "'"
-{-# INLINE defined' #-}
-defined' p = fmap L.defined (satisfy p')
-  where p' Defined { L.defined = d } = p d
-        p' _ = False
-{-# INLINE defined #-}
-defined k = defined' (== k) <?> "'" ++ show k ++ "'"
-{-# INLINE variable #-}
-variable = fmap name (satisfy p) <?> "variable"
-  where p L.Var{} = True
-        p _ = False
-{-# INLINE number #-}
-number = fmap value (satisfy p) <?> "number"
-  where p Number{} = True
-        p _ = False
-{-# INLINE atom #-}
-atom = fmap name (keyword' (const True)) <?> "atom"
-
--- Combinators.
-
-parens, bracks :: Parser a -> Parser a
-{-# INLINE parens #-}
-parens p = between (punct LParen) (punct RParen) p
-{-# INLINE bracks #-}
-bracks p = between (punct LBrack) (punct RBrack) p
-
--- Build an expression parser from a binary-connective parser
--- and a leaf parser.
-binExpr :: Parser a -> Parser (a -> a -> Parser a) -> Parser a
-binExpr leaf op = do
-  lhs <- leaf
-  do { f <- op; rhs <- binExpr leaf op; f lhs rhs } <|> return lhs
-
--- Parsing clauses.
-
--- Parse as many things as possible until EOF or an include statement.
-section :: (Tag -> Bool) -> Parser (Maybe IncludeStatement)
-section included = skipMany (input included) >> (fmap Just include <|> (eof >> return Nothing))
-
--- A single non-include clause.
-input :: (Tag -> Bool) -> Parser ()
-input included = declaration Cnf (formulaIn cnf) <|>
-                 declaration Fof (formulaIn fof) <|>
-                 declaration Tff (\tag -> formulaIn tff tag <|> typeDeclaration)
-  where {-# INLINE declaration #-}
-        declaration k m = do
-          keyword k
-          parens $ do
-            t <- tag
-            punct Comma
-            -- Don't bother typechecking clauses that we are not
-            -- supposed to include in the problem (seems in the
-            -- spirit of TPTP's include mechanism)
-            if included t then m t else balancedParens
-          punct Dot
-          return ()
-        formulaIn lang tag = do
-          k <- kind
-          punct Comma
-          form <- lang
-          newFormula (k tag form)
-        balancedParens = skipMany (parens balancedParens <|> (satisfy p >> return ()))
-        p Punct{L.kind=LParen} = False
-        p Punct{L.kind=RParen} = False
-        p _ = True
-
--- A TPTP kind.
-kind :: Parser (Tag -> Form -> Input Form)
-kind = axiom Axiom <|> axiom Hypothesis <|> axiom Definition <|>
-       axiom Assumption <|> axiom Lemma <|> axiom Theorem <|>
-       general Conjecture Form.Conjecture <|>
-       general NegatedConjecture Form.Axiom <|>
-       general Question Form.Question
-  where axiom t = general t Form.Axiom
-        general k kind = keyword k >> return (mk kind)
-        mk kind tag form =
-          Input { Form.tag = tag,
-                  Form.kind = kind,
-                  Form.what = form }
-
--- A formula name.
-tag :: Parser Tag
-tag = atom <|> fmap (BS.pack . show) number <?> "clause name"
-
--- An include declaration.
-include :: Parser IncludeStatement
-include = do
-  keyword L.Include
-  res <- parens $ do
-    name <- atom <?> "quoted filename"
-    clauses <- do { punct Comma
-                  ; fmap Just (bracks (sepBy1 tag (punct Comma))) } <|> return Nothing
-    return (Include name clauses)
-  punct Dot
-  return res
-
--- Inserting types, functions and clauses.
-
-newFormula :: Input Form -> Parser ()
-newFormula input = do
-  MkState p t f v i n <- getState
-  putState (MkState (input:p) t f Map.empty i n)
-  
-newNameFrom :: Named a => Closed () -> a -> (Closed (), Name)
-newNameFrom n name = (close_ n' (return ()), open n')
-  where n' = close_ n (newName name)
-
-{-# INLINE findType #-}
-findType :: BS.ByteString -> Parser Type
-findType name = do
-  MkState p t f v i n <- getState
-  case Map.lookup name t of
-    Nothing -> do
-      let (n', name') = newNameFrom n name
-          ty = Type { tname = name', tmonotone = Infinite, tsize = Infinite }
-      putState (MkState p (Map.insert name ty t) f v i n')
-      return ty
-    Just x -> return x
-
-newFunction :: BS.ByteString -> FunType -> Parser (Name ::: FunType)
-newFunction name ty' = do
-  f@(_ ::: ty) <- lookupFunction ty' name
-  unless (ty == ty') $ do
-    fatalError $ "Constant " ++ BS.unpack name ++
-                 " was declared to have type " ++ prettyShow ty' ++
-                 " but already has type " ++ prettyShow ty
-  return f
-
-{-# INLINE applyFunction #-}
-applyFunction :: BS.ByteString -> [Term] -> Type -> Parser Term
-applyFunction name args' res = do
-  i <- individual
-  f@(_ ::: ty) <- lookupFunction (FunType (replicate (length args') i) res) name
-  unless (map typ args' == args ty) $ typeError f args'
-  return (f :@: args')
-
-{-# NOINLINE typeError #-}
-typeError f@(x ::: ty) args' = do
-    let plural 1 x y = x 
-        plural _ x y = y
-    fatalError $ "Type mismatch in term '" ++ prettyShow (f :@: args') ++ "': " ++
-                 "Constant " ++ prettyShow x ++
-                 if length (args ty) == length args' then
-                   " has type " ++ prettyShow ty ++
-                   " but was applied to " ++ plural (length args') "an argument" "arguments" ++
-                   " of type " ++ prettyShow (map typ args')
-                 else
-                   " has arity " ++ show (length args') ++
-                   " but was applied to " ++ show (length (args ty)) ++
-                   plural (length (args ty)) " argument" " arguments"
-
-{-# INLINE lookupFunction #-}
-lookupFunction :: FunType -> BS.ByteString -> Parser (Name ::: FunType)
-lookupFunction def name = do
-  MkState p t f v i n <- getState
-  case Map.lookup name f of
-    Nothing -> do
-      let (n', name') = newNameFrom n name
-          decl = name' ::: def
-      putState (MkState p t (Map.insert name decl f) v i n')
-      return decl
-    Just f -> return f
-
--- The type $i (anything whose type is not specified gets this type)
-{-# INLINE individual #-}
-individual :: Parser Type
-individual = do
-  MkState _ _ _ _ i _ <- getState
-  return i
-
--- Parsing formulae.
-
-cnf, tff, fof :: Parser Form
-cnf =
-  let ?binder = fatalError "Can't use quantifiers in CNF"
-      ?ctx = Nothing
-  in fmap (ForAll . bind) formula
-tff =
-  let ?binder = varDecl True
-      ?ctx = Just Map.empty
-  in formula
-fof =
-  let ?binder = varDecl False
-      ?ctx = Just Map.empty
-  in formula
-
--- We cannot always know whether what we are parsing is a formula or a
--- term, since we don't have lookahead. For example, p(x) might be a
--- formula, but in p(x)=y, p(x) is a term.
---
--- To deal with this, we introduce the Thing datatype.
--- A thing is either a term or a formula, or a literal that we don't know
--- if it should be a term or a formula. Instead of a separate formula-parser
--- and term-parser we have a combined thing-parser.
-data Thing = Apply !BS.ByteString ![Term]
-           | Term !Term
-           | Formula !Form
-
-instance Show Thing where
-  show (Apply f []) = BS.unpack f
-  show (Apply f args) =
-    BS.unpack f ++
-      case args of
-        [] -> ""
-        args -> prettyShow args
-  show (Term t) = prettyShow t
-  show (Formula f) = prettyShow f
-
--- However, often we do know whether we want a formula or a term,
--- and there it's best to use a specialised parser (not least because
--- the error messages are better). For that reason, our parser is
--- parametrised on the type of thing you want to parse. We have two
--- main parsers:
---   * 'term' parses an atomic expression
---   * 'formula' parses an arbitrary expression
--- You can instantiate 'term' for Term, Form or Thing; in each case
--- you get an appropriate parser. You can instantiate 'formula' for
--- Form or Thing.
-
--- Types for which a term f(...) is a valid literal. These are the types on
--- which you can use 'term'.
-class TermLike a where
-  -- Convert from a Thing.
-  fromThing :: Thing -> Parser a
-  -- Parse a variable occurrence as a term on its own, if that's allowed.
-  var :: (?ctx :: Maybe (Map BS.ByteString Variable)) => Parser a
-  -- A parser for this type.
-  parser :: (?binder :: Parser Variable,
-             ?ctx :: Maybe (Map BS.ByteString Variable)) => Parser a
-
-instance TermLike Form where
-  {-# INLINE fromThing #-}
-  fromThing t@(Apply x xs) = fmap (Literal . Pos . Tru) (applyFunction x xs O)
-  fromThing (Term _) = mzero
-  fromThing (Formula f) = return f
-  -- A variable itself is not a valid formula.
-  var = mzero
-  parser = formula
-
-instance TermLike Term where
-  {-# INLINE fromThing #-}
-  fromThing t@(Apply x xs) = individual >>= applyFunction x xs
-  fromThing (Term t) = return t
-  fromThing (Formula _) = mzero
-  parser = term
-  var = do
-    x <- variable
-    case ?ctx of
-      Nothing -> do
-        MkState p t f vs i n <- getState
-        case Map.lookup x vs of
-          Just v -> return (Var v)
-          Nothing -> do
-            let (n', name) = newNameFrom n x
-                v = name ::: i
-            putState (MkState p t f (Map.insert x v vs) i n')
-            return (Var v)
-      Just ctx ->
-        case Map.lookup x ctx of
-          Just v -> return (Var v)
-          Nothing -> fatalError $ "unbound variable " ++ BS.unpack x
-
-instance TermLike Thing where
-  fromThing = return
-  var = fmap Term var
-  parser = formula
-
--- Types that can represent formulae. These are the types on which
--- you can use 'formula'.
-class TermLike a => FormulaLike a where
-  fromFormula :: Form -> a
-instance FormulaLike Form where fromFormula = id
-instance FormulaLike Thing where fromFormula = Formula
-
--- An atomic expression.
-{-# SPECIALISE term :: (?binder :: Parser Variable, ?ctx :: Maybe (Map BS.ByteString Variable)) => Parser Term #-}
-{-# SPECIALISE term :: (?binder :: Parser Variable, ?ctx :: Maybe (Map BS.ByteString Variable)) => Parser Form #-}
-{-# SPECIALISE term :: (?binder :: Parser Variable, ?ctx :: Maybe (Map BS.ByteString Variable)) => Parser Thing #-}
-term :: (?binder :: Parser Variable, ?ctx :: Maybe (Map BS.ByteString Variable), TermLike a) => Parser a
-term = function <|> var <|> parens parser
-  where {-# INLINE function #-}
-        function = do
-          x <- atom
-          args <- parens (sepBy1 term (punct Comma)) <|> return []
-          fromThing (Apply x args)
-
-literal, unitary, quantified, formula ::
-  (?binder :: Parser Variable, ?ctx :: Maybe (Map BS.ByteString Variable), FormulaLike a) => Parser a
-{-# INLINE literal #-}
-literal = true <|> false <|> binary <?> "literal"
-  where {-# INLINE true #-}
-        true = do { defined DTrue; return (fromFormula (And S.Nil)) }
-        {-# INLINE false #-}
-        false = do { defined DFalse; return (fromFormula (Or S.Nil)) }
-        binary = do
-          x <- term :: Parser Thing
-          let {-# INLINE f #-}
-              f p sign = do
-               punct p
-               lhs <- fromThing x :: Parser Term
-               rhs <- term :: Parser Term
-               let form = Literal . sign $ lhs :=: rhs
-               when (typ lhs /= typ rhs) $
-                 fatalError $ "Type mismatch in equality '" ++ prettyShow form ++ 
-                              "': left hand side has type " ++ prettyShow (typ lhs) ++
-                              " but right hand side has type " ++ prettyShow (typ rhs)
-               return (fromFormula form)
-          f Eq Pos <|> f Neq Neg <|> fromThing x
-
-{-# SPECIALISE unitary :: (?binder :: Parser Variable, ?ctx :: Maybe (Map BS.ByteString Variable)) => Parser Form #-}
-{-# SPECIALISE unitary :: (?binder :: Parser Variable, ?ctx :: Maybe (Map BS.ByteString Variable)) => Parser Thing #-}
-unitary = negation <|> quantified <|> literal
-  where {-# INLINE negation #-}
-        negation = do
-          punct L.Not
-          fmap (fromFormula . Not) (unitary :: Parser Form)
-
-{-# INLINE quantified #-}
-quantified = do
-  q <- (punct L.ForAll >> return ForAll) <|>
-       (punct L.Exists >> return Exists)
-  vars <- bracks (sepBy1 ?binder (punct Comma))
-  let Just ctx = ?ctx
-      ctx' = foldl' (\m v -> Map.insert (Name.base (Name.name v)) v m) ctx vars
-  punct Colon
-  rest <- let ?ctx = Just ctx' in (unitary :: Parser Form)
-  return (fromFormula (q (Bind (NameMap.fromList vars) rest)))
-
--- A general formula.
-{-# SPECIALISE formula :: (?binder :: Parser Variable, ?ctx :: Maybe (Map BS.ByteString Variable)) => Parser Form #-}
-{-# SPECIALISE formula :: (?binder :: Parser Variable, ?ctx :: Maybe (Map BS.ByteString Variable)) => Parser Thing #-}
-formula = do
-  x <- unitary :: Parser Thing
-  let binop op t u = op (S.Unit t `S.append` S.Unit u)
-      {-# INLINE connective #-}
-      connective p op = do
-        punct p
-        lhs <- fromThing x
-        rhs <- formula :: Parser Form
-        return (fromFormula (op lhs rhs))
-  connective L.And (binop And) <|> connective L.Or (binop Or) <|>
-   connective Iff Equiv <|>
-   connective L.Implies (Connective Implies) <|>
-   connective L.Follows (Connective Follows) <|>
-   connective L.Xor (Connective Xor) <|>
-   connective L.Nor (Connective Nor) <|>
-   connective L.Nand (Connective Nand) <|>
-   fromThing x
-
--- varDecl True: parse a typed variable binding X:a or an untyped one X
--- varDecl False: parse an untyped variable binding X
-varDecl :: Bool -> Parser Variable
-varDecl typed = do
-  x <- variable
-  ty <- do { punct Colon;
-             when (not typed) $
-               fatalError "Used a typed quantification in an untyped formula";
-             type_ } <|> individual
-  MkState p t f v i n <- getState
-  let (n', name) = newNameFrom n x
-  putState (MkState p t f v i n')
-  return (name ::: ty)
-
--- Parse a type
-type_ :: Parser Type
-type_ =
-  do { name <- atom; findType name } <|>
-  do { defined DI; individual }
-
--- A little data type to help with parsing types.
-data Type_ = TType | Fun [Type] Type | Prod [Type]
-
-prod :: Type_ -> Type_ -> Parser Type_
-prod (Prod tys) (Prod tys2) | not (O `elem` tys ++ tys2) = return $ Prod (tys ++ tys2)
-prod _ _ = fatalError "invalid type"
-
-arrow :: Type_ -> Type_ -> Parser Type_
-arrow (Prod ts) (Prod [x]) = return $ Fun ts x
-arrow _ _ = fatalError "invalid type"
-
-leaf :: Parser Type_
-leaf = do { defined DTType; return TType } <|>
-       do { defined DO; return (Prod [O]) } <|>
-       do { ty <- type_; return (Prod [ty]) } <|>
-       parens compoundType
-
-compoundType :: Parser Type_
-compoundType = leaf `binExpr` (punct Times >> return prod)
-                    `binExpr` (punct FunArrow >> return arrow)
-
-typeDeclaration :: Parser ()
-typeDeclaration = do
-  keyword L.Type
-  punct Comma
-  let manyParens p = parens (manyParens p) <|> p
-  manyParens $ do
-    name <- atom
-    punct Colon
-    res <- compoundType
-    case res of
-      TType -> do { findType name; return () }
-      Fun args res -> do { newFunction name (FunType args res); return () }
-      Prod [res] -> do { newFunction name (FunType [] res); return () }
-      _ -> fatalError "invalid type"
diff --git a/Jukebox/TPTP/FindFile.hs b/Jukebox/TPTP/FindFile.hs
deleted file mode 100644
--- a/Jukebox/TPTP/FindFile.hs
+++ /dev/null
@@ -1,41 +0,0 @@
-module Jukebox.TPTP.FindFile where
-
-import System.FilePath
-import System.Directory(doesFileExist)
-import System.Environment
-import Control.Applicative
-import Control.Exception
-import Control.Monad
-import Prelude hiding (catch)
-import Jukebox.Options
-import Data.Traversable(sequenceA)
-
-findFile :: [FilePath] -> FilePath -> IO (Maybe FilePath)
-findFile [] file = return Nothing
-findFile (path:paths) file = do
-  let candidate = path </> file
-  exists <- doesFileExist candidate
-  if exists then return (Just candidate)
-   else findFile paths file
-
-findFileTPTP :: [FilePath] -> FilePath -> IO (Maybe FilePath)
-findFileTPTP dirs file = do
-  let candidates = [file, "Problems" </> file,
-                    "Problems" </> take 3 file </> file]
-  fmap msum (mapM (findFile dirs) candidates)
-
-getTPTPDirs :: IO [FilePath]
-getTPTPDirs = do { dir <- getEnv "TPTP"; return [dir] } `catch` f
-  where f :: IOException -> IO [FilePath]
-        f _ = return []
-
-findFileFlags =
-  concat <$>
-  sequenceA [
-    pure ["."],
-    flag "root"
-      ["Extra directories that will be searched for TPTP input files."]
-      []
-      argFiles,
-    io getTPTPDirs
-    ]
diff --git a/Jukebox/TPTP/Lexer.x b/Jukebox/TPTP/Lexer.x
deleted file mode 100644
--- a/Jukebox/TPTP/Lexer.x
+++ /dev/null
@@ -1,223 +0,0 @@
--- -*- mode: haskell -*-
-
--- Roughly taken from the TPTP syntax reference
-{
-{-# OPTIONS_GHC -O2 -fno-warn-deprecated-flags #-}
-{-# LANGUAGE BangPatterns #-}
-module Jukebox.TPTP.Lexer(
-  scan,
-  Pos(..),
-  Token(..),
-  Punct(..),
-  Defined(..),
-  Keyword(..),
-  TokenStream(..),
-  Contents(..)) where
-
-import qualified Data.ByteString.Char8 as BS
-import qualified Data.ByteString.Lazy.Char8 as BSL
-import Data.ByteString.Lazy.Internal
-import Data.Word
-import Data.Char
-}
-
-$alpha = [a-zA-Z0-9_]
-$anything = [. \n]
-@quoted = ($printable # [\\']) | \\ $printable
-@dquoted = ($printable # [\\\"]) | \\ $printable
-
-tokens :-
--- Comments and whitespace
-"%" .* ;
-"/*" (($anything # \*)* "*"+
-      ($anything # [\/\*]))*
-     ($anything # \*)* "*"* "*/" ; -- blech!
-$white+ ;
-
--- Keywords.
-"thf" { k Thf }
-"tff" { k Tff }
-"fof" { k Fof }
-"cnf" { k Cnf }
-"axiom" { k Axiom }
-"hypothesis" { k Hypothesis }
-"definition" { k Definition }
-"assumption" { k Assumption }
-"lemma" { k Lemma }
-"theorem" { k Theorem }
-"conjecture" { k Conjecture }
-"negated_conjecture" { k NegatedConjecture }
-"question" { k Question }
-"plain" { k Plain }
-"fi_domain" { k FiDomain }
-"fi_hypothesis" { k FiHypothesis }
-"fi_predicates" { k FiPredicates }
-"type" { k Type }
-"unknown" { k Unknown }
-"include" { k Include }
--- Defined symbols.
-"$true" { d DTrue }
-"$false" { d DFalse }
-"$equal" { d DEqual }
-"$distinct" { d DDistinct }
-"$itef" { d DItef }
-"$itett" | "$itetf" { d DItet }
-"$o" | "$oType" { d DO }
-"$i" | "$iType" { d DI }
-"$tType" { d DTType }
--- Atoms.
-"$"{0,2} [a-z] $alpha* { Atom Normal . copy }
--- Atoms with funny quoted names (here we diverge from the official
--- syntax, which only allows the escape sequences \\ and \' in quoted
--- atoms: we allow \ to be followed by any printable character)
-"'"  @quoted+ "'" { Atom Normal . unquote }
--- Vars are easy :)
-[A-Z][$alpha]* { Var . copy }
--- Distinct objects, which are double-quoted
-\" @dquoted+  \" { DistinctObject . unquote }
--- Integers
-[\+\-]? (0 | [1-9][0-9]*)/($anything # $alpha) { Number . readNumber }
-
--- Operators (FOF)
-"("  { p LParen }  ")"   { p RParen }  "["  { p LBrack }   "]"  { p RBrack }
-","  { p Comma }   "."   { p Dot }     "|"  { p Or }       "&"  { p And }
-"~"  { p Not }     "<=>" { p Iff }     "=>" { p Implies }  "<=" { p Follows }
-"<~>"{ p Xor }     "~|"  { p Nor }     "~&" { p Nand }     "="  { p Eq }
-"!=" { p Neq }     "!"   { p ForAll }  "?"  { p Exists }   ":=" { p Let }
-":-" { p LetTerm }
--- Operators (TFF)
-":" { p Colon }    "*"   { p Times }   "+"  { p Plus }     ">"  { p FunArrow }
--- Operators (THF)
-"^"  { p Lambda } "@" { p Apply }  "!!" { p ForAllLam }  "??"  { p ExistsLam }
-"@+" { p Some }   "@-" { p The }   "<<" { p Subtype }    "-->" { p SequentArrow }
-"!>" { p DependentProduct }        "?*" { p DependentSum }
-
-{
-data Pos = Pos {-# UNPACK #-} !Word {-# UNPACK #-} !Word deriving Show
-data Token = Atom { keyword :: !Keyword, name :: !BS.ByteString }
-           | Defined { defined :: !Defined  }
-           | Var { name :: !BS.ByteString }
-           | DistinctObject { name :: !BS.ByteString }
-           | Number { value :: !Integer }
-           | Punct { kind :: !Punct }
-           | Eof
-           | Error
-
-data Keyword = Normal
-             | Thf | Tff | Fof | Cnf
-             | Axiom | Hypothesis | Definition | Assumption
-             | Lemma | Theorem | Conjecture | NegatedConjecture | Question
-             | Plain | FiDomain | FiHypothesis | FiPredicates | Type | Unknown
-             | Include deriving (Eq, Ord)
-
-instance Show Keyword where
-  show x =
-    case x of {
-      Normal -> "normal";
-      Thf -> "thf"; Tff -> "tff"; Fof -> "fof"; Cnf -> "cnf";
-      Axiom -> "axiom"; Hypothesis -> "hypothesis"; Definition -> "definition";
-      Assumption -> "assumption"; Lemma -> "lemma"; Theorem -> "theorem";
-      Conjecture -> "conjecture"; NegatedConjecture -> "negated_conjecture";
-      Question -> "question"; Plain -> "plain"; FiDomain -> "fi_domain";
-      FiHypothesis -> "fi_hypothesis"; FiPredicates -> "fi_predicates";
-      Type -> "type"; Unknown -> "unknown"; Include -> "include" }
-
--- We only include defined names that need special treatment from the
--- parser here: you can freely make up any other names starting with a
--- '$' and they get turned into Atoms.
-data Defined = DTrue | DFalse | DEqual | DDistinct | DItef | DItet
-             | DO | DI | DTType deriving (Eq, Ord)
-
-instance Show Defined where
-  show x =
-    case x of {
-      DTrue -> "$true"; DFalse -> "$false"; DEqual -> "$equal";
-      DDistinct -> "$distinct"; DItef -> "$itef"; DItet -> "$itet";
-      DO -> "$o"; DI -> "$i"; DTType -> "$tType" }
-
-data Punct = LParen | RParen | LBrack | RBrack | Comma | Dot
-           | Or | And | Not | Iff | Implies | Follows | Xor | Nor | Nand
-           | Eq | Neq | ForAll | Exists | Let | LetTerm -- FOF
-           | Colon | Times | Plus | FunArrow -- TFF
-           | Lambda | Apply | ForAllLam | ExistsLam
-           | DependentProduct | DependentSum | Some | The
-           | Subtype | SequentArrow -- THF
-             deriving (Eq, Ord)
-
-instance Show Punct where
-  show x =
-    case x of {
-      LParen -> "("; RParen -> ")"; LBrack -> "["; RBrack -> "]";
-      Comma -> ","; Dot -> "."; Or -> "|"; And -> "&"; Not -> "~";
-      Iff -> "<=>"; Implies -> "=>"; Follows -> "<="; Xor -> "<~>";
-      Nor -> "~|"; Nand -> "~&"; Eq -> "="; Neq -> "!="; ForAll -> "!";
-      Exists -> "?"; Let -> ":="; Colon -> ":"; Times -> "*"; Plus -> "+";
-      FunArrow -> ">"; Lambda -> "^"; Apply -> "@"; ForAllLam -> "!!";
-      ExistsLam -> "??"; Some -> "@+"; The -> "@-"; Subtype -> "<<";
-      SequentArrow -> "-->"; DependentProduct -> "!>"; DependentSum -> "?*" }
-
-p x = const (Punct x)
-k x = Atom x . copy
-d x = const (Defined x)
-
-copy :: BS.ByteString -> BS.ByteString
-copy = id -- could change to a string interning function later
-
-unquote :: BS.ByteString -> BS.ByteString
-unquote x =
-  case BSL.toChunks (BSL.tail (unquote' x)) of
-    [] -> BS.empty
-    [x] -> copy x
-    xs -> BS.concat xs
-
-unquote' :: BS.ByteString -> BSL.ByteString
-unquote' x | BS.null z = chunk (BS.init y) Empty
-           | otherwise = chunk y (BS.index z 1 `BSL.cons'` unquote' (BS.drop 2 z))
-           where (y, z) = BS.break (== '\\') x
-    
-readNumber :: BS.ByteString -> Integer
-readNumber x | BS.null r = n
-  where Just (n, r) = BS.readInteger x
-
--- The main scanner function, heavily modified from Alex's posn-bytestring wrapper.
-
-data TokenStream = At {-# UNPACK #-} !Pos !Contents
-data Contents = Cons !Token TokenStream
-
-scan xs = go (Input (Pos 1 1) '\n' BS.empty xs)
-  where go inp@(Input pos _ x xs) =
-          case alexScan inp 0 of
-                AlexEOF -> let t = At pos (Cons Eof t) in t
-                AlexError _ -> let t = At pos (Cons Error t) in t
-                AlexSkip  inp' len -> go inp'
-                AlexToken inp' len act ->
-                  let token | len <= BS.length x = BS.take len x
-                            | otherwise = BS.concat (BSL.toChunks (BSL.take (fromIntegral len) (chunk x xs)))
-                  in At pos (act token `Cons` go inp')
-
-data AlexInput = Input {-# UNPACK #-} !Pos {-# UNPACK #-} !Char {-# UNPACK #-} !BS.ByteString BSL.ByteString
-
-alexInputPrevChar :: AlexInput -> Char
-alexInputPrevChar (Input p c x xs) = c
-
-{-# INLINE alexGetByte #-}
-alexGetByte :: AlexInput -> Maybe (Word8,AlexInput)
-alexGetByte i = fmap f (alexGetChar i)
-  where f (c, i') = (fromIntegral (ord c), i')
-{-# INLINE alexGetChar #-}
-alexGetChar :: AlexInput -> Maybe (Char,AlexInput)
-alexGetChar (Input p _ x xs) | not (BS.null x) = getCharNonEmpty p x xs
-alexGetChar (Input p _ _ (Chunk x xs)) = getCharNonEmpty p x xs
-alexGetChar (Input p _ _ Empty) = Nothing
-{-# INLINE getCharNonEmpty #-}
-getCharNonEmpty p x xs =
-  let !c = BS.head x
-      !next = Input (advance p c) c (BS.tail x) xs
-  in Just (c, next)
-
-{-# INLINE advance #-}
-advance :: Pos -> Char -> Pos
-advance (Pos l c) '\t' = Pos  l    (c+8 - (c-1) `mod` 8)
-advance (Pos l c) '\n' = Pos (l+1) 1
-advance (Pos l c) _    = Pos  l    (c+1)
-}
diff --git a/Jukebox/TPTP/ParseProblem.hs b/Jukebox/TPTP/ParseProblem.hs
deleted file mode 100644
--- a/Jukebox/TPTP/ParseProblem.hs
+++ /dev/null
@@ -1,83 +0,0 @@
-{-# LANGUAGE ScopedTypeVariables #-}
-module Jukebox.TPTP.ParseProblem where
-
-import Jukebox.ProgressBar
-import Jukebox.TPTP.FindFile
-import Jukebox.TPTP.ClauseParser
-import Jukebox.TPTP.Lexer hiding (Include, Error)
-import Jukebox.TPTP.Parsec
-import Jukebox.TPTP.Print
-import qualified Jukebox.TPTP.Lexer as L
-import Control.Monad.Error
-import Jukebox.Form hiding (Pos)
-import qualified Data.ByteString.Lazy.Char8 as BSL
-import qualified Data.ByteString.Char8 as BS
-import Control.Monad.Identity
-import Control.Exception
-import Prelude hiding (catch)
-import Data.List
-import Jukebox.Name
-
-parseProblem :: [FilePath] -> FilePath -> IO (Either String (Problem Form))
-parseProblem dirs name = withProgressBar $ \pb -> parseProblemWith (findFileTPTP dirs) pb name
-
-parseProblemWith :: (FilePath -> IO (Maybe FilePath)) -> ProgressBar -> FilePath -> IO (Either String (Problem Form))
-parseProblemWith findFile progressBar name = runErrorT (fmap finalise (parseFile name Nothing "<command line>" (Pos 0 0) initialState))
-  where err :: String -> Pos -> String -> ErrorT String IO a
-        err file (Pos l c) msg = throwError msg'
-          where msg' = "Error at " ++ file ++ " (line " ++ show l ++ ", column " ++ show c ++ "):\n" ++ msg
-        liftMaybeIO :: IO (Maybe a) -> FilePath -> Pos -> String -> ErrorT String IO a
-        liftMaybeIO m file pos msg = do
-          x <- liftIO m
-          case x of
-            Nothing -> err file pos msg
-            Just x -> return x
-        liftEitherIO :: IO (Either a b) -> FilePath -> Pos -> (a -> String) -> ErrorT String IO b
-        liftEitherIO m file pos msg = do
-          x <- liftIO m
-          case x of
-            Left e -> err file pos (msg e)
-            Right x -> return x
-
-        parseFile :: FilePath -> Maybe [Tag] -> FilePath -> Pos ->
-                     ParseState -> ErrorT FilePath IO ParseState
-        parseFile name clauses file0 pos st = do
-          file <- liftMaybeIO (findFile name) file0 pos ("File " ++ name ++ " not found")
-          liftIO $ enter progressBar $ "Reading " ++ file
-          contents <- liftEitherIO
-                        (fmap Right (BSL.readFile file >>= tickOnRead progressBar)
-                          `catch` (\(e :: IOException) -> return (Left e)))
-                        file (Pos 0 0) show
-          let s = UserState st (scan contents)
-          fmap userState (parseSections clauses file s)
-
-        parseSections :: Maybe [Tag] -> FilePath -> ParsecState -> ErrorT String IO ParsecState
-        parseSections clauses file s =
-          let report UserState{userStream = At _ (Cons Eof _)} =
-                ["Unexpected end of file"]
-              report UserState{userStream = At _ (Cons L.Error _)} =
-                ["Lexical error"]
-              report UserState{userStream = At _ (Cons t _)} =
-                ["Unexpected " ++ show t] in
-          case run report (section (included clauses)) s of
-            (UserState{userStream=At pos _}, Left e) ->
-              err file pos (concat (intersperse "\n" e))
-            (s'@UserState{userStream=At _ (Cons Eof _)}, Right Nothing) -> do
-              liftIO $ leave progressBar
-              return s'
-            (UserState{userStream=stream@(At pos _),userState=state},
-             Right (Just (Include name clauses'))) -> do
-              s' <- parseFile (BS.unpack name) (clauses `merge` clauses') file pos state
-              parseSections clauses file (UserState s' stream)
-
-        included :: Maybe [Tag] -> Tag -> Bool
-        included Nothing _ = True
-        included (Just xs) x = x `elem` xs
-
-        merge :: Maybe [Tag] -> Maybe [Tag] -> Maybe [Tag]
-        merge Nothing x = x
-        merge x Nothing = x
-        merge (Just xs) (Just ys) = Just (xs `intersect` ys)
-
-        finalise :: ParseState -> Problem Form
-        finalise (MkState p _ _ _ _ n) = close_ n (return (reverse p))
diff --git a/Jukebox/TPTP/ParseSnippet.hs b/Jukebox/TPTP/ParseSnippet.hs
deleted file mode 100644
--- a/Jukebox/TPTP/ParseSnippet.hs
+++ /dev/null
@@ -1,45 +0,0 @@
--- Parse little bits of TPTP, e.g. a prelude for a particular tool.
-
-module Jukebox.TPTP.ParseSnippet where
-
-import Jukebox.TPTP.ClauseParser as TPTP.ClauseParser
-import Jukebox.TPTP.Parsec as TPTP.Parsec
-import Jukebox.TPTP.Lexer
-import Jukebox.Name
-import Jukebox.Form
-import qualified Data.ByteString.Lazy.Char8 as BSL
-import qualified Data.ByteString.Char8 as BS
-import Control.Applicative
-import qualified Jukebox.Map as Map
-import Data.List
-
-tff, cnf :: [(String, Type)] -> [(String, Function)] -> String -> NameM Form
-tff = form TPTP.ClauseParser.tff
-cnf = form TPTP.ClauseParser.cnf
-
-form parser types funs str = supply (form' parser types funs str)
-
-form' parser types funs str cl =
-  let state0 = MkState [] (pack types) (pack funs) Map.empty iType cl
-      pack xs = Map.fromList [(BS.pack x, y) | (x, y) <- xs]
-      unpack m = [(BS.unpack x, y) | (x, y) <- Map.toList m]
-      iType =
-        case lookup "$i" types of
-          Just x -> x
-          Nothing -> error "ParseSnippet: use explicit type declarations" in
-  case run_ (parser <* eof)
-            (UserState state0 (scan (BSL.pack str))) of
-    Ok (UserState state (At _ (Cons Eof _))) res ->
-      case state of
-        MkState _ types' funs' vars _ _
-          | pack types /= types' ->
-            error $ "ParseSnippet: type implicitly defined: " ++
-                    show (map snd (unpack types' \\ types))
-          | pack funs /= funs' ->
-            error $ "ParseSnippet: function implicitly defined: " ++
-                    show (map snd (unpack funs' \\ funs))
-        MkState _ _ _ _ _ cl' ->
-          fmap (const res) cl'
-    Ok{} -> error "ParseSnippet: lexical error"
-    TPTP.Parsec.Error _ msg -> error $ "ParseSnippet: parse error: " ++ msg
-    Expected _ exp -> error $ "ParseSnippet: parse error: expected " ++ show exp
diff --git a/Jukebox/TPTP/Parsec.hs b/Jukebox/TPTP/Parsec.hs
deleted file mode 100644
--- a/Jukebox/TPTP/Parsec.hs
+++ /dev/null
@@ -1,174 +0,0 @@
-{-# LANGUAGE RankNTypes, BangPatterns, MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, UndecidableInstances, TypeFamilies #-}
-module Jukebox.TPTP.Parsec where
-
-import Control.Applicative
-import Control.Monad
-import Data.List
-
--- Parser type and monad instances
-
-newtype Parsec a b = Parsec
-  { runParsec :: forall c.
-                 (b -> Reply a c -> a -> Reply a c) -- ok: success
-              -> Reply a c -- err: backtracking failure
-              -> a -> Reply a c }
-
-type Reply a b = [String] -> Result (Position a) b
-
-data Result a b = Ok a b | Error a String | Expected a [String]
-
-{-# INLINE parseError #-}
-parseError :: [String] -> Parsec a b
-parseError e = Parsec (\ok err inp exp -> err (e ++ exp))
-
-{-# INLINE fatalError #-}
-fatalError :: Stream a c => String -> Parsec a b
-fatalError e = Parsec (\ok err inp _ -> Error (position inp) e)
-
-instance Functor (Parsec a) where
-  {-# INLINE fmap #-}
-  fmap f x = x >>= return . f
-
-instance Monad (Parsec a) where
-  {-# INLINE return #-}
-  return x = Parsec (\ok err inp exp -> ok x err inp exp)
-  {-# INLINE (>>=) #-}
-  x >>= f = Parsec (\ok err inp exp  -> runParsec x (\y err inp exp -> runParsec (f y) ok err inp exp) err inp exp)
-  {-# INLINE fail #-}
-  fail _ = parseError []
-
-instance MonadPlus (Parsec a) where
-  {-# INLINE mzero #-}
-  mzero = Parsec (\ok err inp exp -> err exp)
-  {-# INLINE mplus #-}
-  m1 `mplus` m2 = Parsec (\ok err inp exp ->
-    runParsec m1 ok (\exp -> runParsec m2 ok err inp exp) inp exp)
-
-instance Applicative (Parsec a) where
-  {-# INLINE pure #-}
-  pure = return
-  {-# INLINE (<*>) #-}
-  f <*> x = do { f' <- f; x' <- x; return (f' x') }
-  {-# INLINE (*>) #-}
-  (*>) = (>>)
-  {-# INLINE (<*) #-}
-  x <* y = do
-    x' <- x
-    y
-    return x'
-
-instance Alternative (Parsec a) where
-  {-# INLINE empty #-}
-  empty = mzero
-  {-# INLINE (<|>) #-}
-  (<|>) = mplus
-  {-# INLINE some #-}
-  some p = do { x <- nonempty p; xs <- many p; return (x:xs) }
-  {-# INLINE many #-}
-  many p = p' where p' = liftM2 (:) (nonempty p) p' <|> return []
-  -- Stack overflow-avoiding version:
-  -- many p = liftM reverse (p' [])
-  --   where p' !xs = do { x <- nonempty p; p' (x:xs) } `mplus` return xs
-
--- Basic combinators
-
-{-# INLINE nonempty #-}
-nonempty :: Parsec a b -> Parsec a b
-nonempty p = p
-
-{-# INLINE skipSome #-}
-skipSome :: Parsec a b -> Parsec a ()
-skipSome p = p' where p' = nonempty p >> (p' `mplus` return ())
-
-{-# INLINE skipMany #-}
-skipMany :: Parsec a b -> Parsec a ()
-skipMany p = p' where p' = (nonempty p >> p') `mplus` return ()
-
-{-# INLINE (<?>) #-}
-infix 0 <?>
-(<?>) :: Parsec a b -> String -> Parsec a b
-p <?> text = Parsec (\ok err inp exp ->
-  runParsec p ok err inp (text:exp))
-
-{-# INLINE between #-}
-between :: Parsec a b -> Parsec a c -> Parsec a d -> Parsec a d
-between p q r = p *> r <* q
-
-{-# INLINE sepBy1 #-}
-sepBy1 :: Parsec a b -> Parsec a c -> Parsec a [b]
-sepBy1 it sep = liftM2 (:) it (many (sep >> it))
-
--- Running the parser
-
-run_ :: Stream a c => Parsec a b -> a -> Result (Position a) b
-run_ p x = runParsec p ok err x []
-  where ok x _ inp _ = Ok (position inp) x
-        err exp = Expected (position x) (reverse exp)
-
-run :: Stream a c => (Position a -> [String]) -> Parsec a b -> a -> (Position a, Either [String] b)
-run report p ts =
-  case run_ p ts of
-    Ok ts' x -> (ts', Right x)
-    Error ts' e -> (ts', Left [e])
-    Expected ts' e -> (ts', Left (expected (report ts') e))
-
--- Reporting errors
-
-expected :: [String] -> [String] -> [String]
-expected unexpected [] = unexpected ++ ["Unknown error"]
-expected unexpected expected =
-  unexpected ++ [ "Expected " ++ list expected ]
-  where list [exp] = exp
-        list exp = intercalate ", " (init exp) ++ " or " ++ last exp
-
--- Token streams
-
-class Stream a b | a -> b where
-  primToken :: a -> (a -> b -> c) -> c -> (String -> c) -> c
-  type Position a
-  position :: a -> Position a
-
-{-# INLINE next #-}
-next :: Stream a b => Parsec a b
-next = Parsec (\ok err inp exp ->
-  primToken inp (\inp' x -> ok x err inp' exp) (err exp) (Error (position inp)))
-
-{-# INLINE cut #-}
-cut :: Stream a b => Parsec a ()
-cut = Parsec (\ok err inp exp -> ok () (Expected (position inp)) inp [])
-
-{-# INLINE cut' #-}
-cut' :: Stream a b => Parsec a c -> Parsec a c
-cut' p = Parsec (\ok err inp exp -> runParsec p (\x _ inp' _ -> ok x err inp' []) err inp exp)
-
-{-# INLINE satisfy #-}
-satisfy :: Stream a b => (b -> Bool) -> Parsec a b
-satisfy p = do
-  t <- next
-  guard (p t)
-  cut
-  return t
-
-{-# INLINE eof #-}
-eof :: Stream a b => Parsec a ()
-eof = Parsec (\ok err inp exp ->
-  primToken inp (\_ _ -> err ("end of file":exp)) (ok () err inp exp) (Error (position inp)))
-
--- User state
-
-data UserState state stream = UserState { userState :: !state, userStream :: !stream }
-
-instance Stream a b => Stream (UserState state a) b where
-  {-# INLINE primToken #-}
-  primToken (UserState state stream) ok err =
-    primToken stream (ok . UserState state) err
-  type Position (UserState state a) = UserState state a
-  position = id
-
-{-# INLINE getState #-}
-getState :: Parsec (UserState state a) state
-getState = Parsec (\ok err inp@UserState{userState = state} exp -> ok state err inp exp)
-
-{-# INLINE putState #-}
-putState :: state -> Parsec (UserState state a) ()
-putState state = Parsec (\ok err inp@UserState{userStream = stream} exp -> ok () err (UserState state stream) exp)
diff --git a/Jukebox/TPTP/Print.hs b/Jukebox/TPTP/Print.hs
deleted file mode 100644
--- a/Jukebox/TPTP/Print.hs
+++ /dev/null
@@ -1,200 +0,0 @@
--- Pretty-printing of formulae. WARNING: icky code inside!
-{-# LANGUAGE FlexibleContexts, TypeSynonymInstances, TypeOperators, FlexibleInstances #-}
-module Jukebox.TPTP.Print(prettyShow, chattyShow, prettyFormula, prettyProblem, Level(..), Pretty)
-       where
-
-import qualified Data.ByteString.Char8 as BS
-import Data.Char
-import Text.PrettyPrint.HughesPJ
-import qualified Jukebox.TPTP.Lexer as L
-import Jukebox.Form
-import Data.List
-import qualified Jukebox.Map as Map
-import qualified Jukebox.Seq as S
-import qualified Jukebox.NameMap as NameMap
-import Jukebox.NameMap(NameMap)
-import Jukebox.Name
-
-data Level = Normal | Chatty deriving (Eq, Ord)
-
-class Pretty a where
-  pPrint :: Int -> Level -> (Name -> BS.ByteString) -> a -> Doc
-
-instance Pretty Name where
-  pPrint _ _ env x = text (BS.unpack (env x))
-
-pPrintSymbol :: Bool -> Int -> Level -> (Name -> BS.ByteString) -> Name ::: Type -> Doc
-pPrintSymbol full prec lev env (x ::: t)
-  | full || lev >= Chatty = pPrint prec lev env x <> colon <> pPrint prec lev env t
-  | otherwise = pPrint prec lev env x
-
-pPrintBinding prec lev env (x ::: t) =
-  pPrintSymbol (name t /= nameI) prec lev env (x ::: typ t)
-
-pPrintUse prec lev env (x ::: t) =
-  pPrintSymbol False prec lev env (x ::: typ t)
-
-instance Pretty Type where
-  pPrint prec lev env O = pPrint prec lev env nameO
-  pPrint prec lev env t
-    | lev >= Chatty = 
-      hcat . punctuate (text "/") $
-        [text (BS.unpack (escapeAtom (env (tname t))))] ++
-        [size (tmonotone t) | tmonotone t /= Infinite || tsize t /= Infinite] ++
-        [size (tsize t) | tsize t /= Infinite]
-    | otherwise = text (BS.unpack (escapeAtom (env (tname t))))
-    where size Infinite = empty
-          size (Finite n) = int n
-
-instance Show Type where
-  show = chattyShow
-
-instance Show L.Token where
-  show L.Atom{L.name = x} = BS.unpack (escapeAtom x)
-  show L.Defined{L.defined = x} = show x
-  show L.Var{L.name = x} = BS.unpack x
-  show L.DistinctObject{L.name = x} = BS.unpack (quote '"' x)
-  show L.Number{L.value = x} = show x
-  show L.Punct{L.kind = x} = show x
-  show L.Eof = "end of file"
-  show L.Error = "lexical error"
-
-escapeAtom :: BS.ByteString -> BS.ByteString
-escapeAtom s | not (BS.null s') && isLower (BS.head s') && BS.all isNormal s' = s
-             | otherwise = quote '\'' s
-  where isNormal c = isAlphaNum c || c == '_'
-        s' = BS.dropWhile (== '$') s
-
-quote :: Char -> BS.ByteString -> BS.ByteString
-quote c s = BS.concat [BS.pack [c], BS.concatMap escape s, BS.pack [c]]
-  where escape c' | c == c' = BS.pack ['\\', c]
-        escape '\\' = BS.pack "\\\\"
-        escape c = BS.singleton c
-
-instance Pretty FunType where
-  pPrint prec lev env FunType{args = args, res = res} =
-    case args of
-      [] -> pPrint prec lev env res
-      args -> pPrint prec lev env args <+> text ">" <+>
-              pPrint prec lev env res
-
-instance Show FunType where
-  show = chattyShow
-
-instance Pretty [Type] where
-  pPrint prec lev env [arg] = pPrint prec lev env arg
-  pPrint prec lev env args =
-    parens (hsep (intersperse (text "*")
-                  (map (pPrint 0 lev env) args)))
-
-prettyProblem :: (Symbolic a, Pretty a) => String -> Level -> Problem a -> Doc
-prettyProblem family l prob = vcat (map typeDecl (S.unique (types prob')) ++
-                                    map funcDecl (S.unique (functions prob')) ++
-                                    map (prettyInput family l env) prob')
-    where typeDecl ty | name ty `elem` open stdNames || isFof prob' = empty
-                      | otherwise = typeClause ty (text "$tType")
-          funcDecl (f ::: ty) | isFof prob' = empty
-                              | otherwise = typeClause f (pPrint 0 l (escapeAtom . env) ty)
-          typeClause name ty = prettyClause "tff" "type" "type"
-                                      (pPrint 0 l (escapeAtom . env) name <+> colon <+> ty)
-          env = uniquify (S.unique (names prob'))
-          prob' = open prob
-
-prettyClause :: String -> String -> String -> Doc -> Doc
-prettyClause family name kind rest =
-  text family <> parens (sep [text name <> comma <+> text kind <> comma, rest]) <> text "."
-
-instance (Symbolic a, Pretty a) => Show (Problem a) where
-  show = render . prettyProblem "tff" Chatty
-
-prettyInput :: Pretty a => String -> Level -> (Name -> BS.ByteString) -> Input a -> Doc
-prettyInput family l env i = prettyClause family (BS.unpack (tag i)) (show (kind i)) (pPrint 0 l env (what i))
-
-instance Pretty a => Pretty (Input a) where
-  pPrint _ l env = prettyInput "tff" l env
-
-instance Pretty a => Show (Input a) where
-  show = chattyShow
-
-instance Pretty Term where
-  pPrint _ l env (Var v) = pPrintUse 0 l env v
-  pPrint _ l env (f :@: []) = pPrintUse 0 l (escapeAtom . env) f
-  pPrint _ l env (f :@: ts) = pPrintUse 0 l (escapeAtom . env) f <> pPrint 0 l env ts
-  
-instance Pretty [Term] where
-  pPrint _ l env ts = parens (sep (punctuate comma (map (pPrint 0 l env) ts)))
-
-instance Show Term where
-  show = chattyShow
-
-instance Pretty Atomic where
-  pPrint _ l env (t :=: u) = pPrint 0 l env t <> text "=" <> pPrint 0 l env u
-  pPrint _ l env (Tru t) = pPrint 0 l env t
-
-instance Show Atomic where
-  show = chattyShow
-
-instance Pretty Clause where
-  pPrint p l env c@(Clause (Bind vs ts))
-    | and [ name (typ v) == nameI | v <- NameMap.toList vs ] =
-       prettyConnective l p env "$false" "|" (map Literal ts)
-    | otherwise =
-       pPrint p l env (toForm c)
-
-instance Show Clause where
-  show = chattyShow
-
-instance Pretty Form where
-  -- We use two precedences, the lowest for binary connectives
-  -- and the highest for everything else.
-  pPrint p l env (Literal (Pos (t :=: u))) =
-    pPrint 0 l env t <> text "=" <> pPrint 0 l env u
-  pPrint p l env (Literal (Neg (t :=: u))) =
-    pPrint 0 l env t <> text "!=" <> pPrint 0 l env u
-  pPrint p l env (Literal (Pos t)) = pPrint p l env t
-  pPrint p l env (Literal (Neg t)) = pPrint p l env (Not (Literal (Pos t)))
-  pPrint p l env (Not f) = text "~" <> pPrint 1 l env f
-  pPrint p l env (And ts) = prettyConnective l p env "$true" "&" (S.toList ts)
-  pPrint p l env (Or ts) = prettyConnective l p env "$false" "|" (S.toList ts)
-  pPrint p l env (Equiv t u) = prettyConnective l p env undefined "<=>" [t, u]
-  pPrint p l env (ForAll (Bind vs f)) = prettyQuant l env "!" vs f
-  pPrint p l env (Exists (Bind vs f)) = prettyQuant l env "?" vs f
-  pPrint p l env (Connective c t u) = prettyConnective l p env (error "pPrint: Connective") (show c) [t, u]
-
-instance Show Form where
-  show = chattyShow
-
-instance Show Connective where
-  show Implies = "=>"
-  show Follows = "<="
-  show Xor = "<~>"
-  show Nor = "~|"
-  show Nand = "~&"
-
-prettyConnective l p env ident op [] = text ident
-prettyConnective l p env ident op [x] = pPrint p l env x
-prettyConnective l p env ident op (x:xs) =
-  prettyParen (p > 0) $
-    sep (ppr x:[ nest 2 (text op <+> ppr x) | x <- xs ])
-      where ppr = pPrint 1 l env
-            
-prettyParen False = id
-prettyParen True = parens
-
-prettyQuant l env q vs f | Map.null vs = pPrint 1 l env f
-prettyQuant l env q vs f =
-  sep [text q <> brackets (sep (punctuate comma (map (pPrintBinding 0 l env) (Map.elems vs)))) <> colon,
-       nest 2 (pPrint 1 l env f)]
-
-instance Show Kind where
-  show Axiom = "axiom"
-  show Conjecture = "conjecture"
-  show Question = "question"
-
-prettyShow, chattyShow :: Pretty a => a -> String
-prettyShow = render . pPrint 0 Normal base
-chattyShow = render . pPrint 0 Chatty (BS.pack . show)
-
-prettyFormula :: (Pretty a, Symbolic a) => a -> String
-prettyFormula prob = render . pPrint 0 Normal env $ prob
-  where env = uniquify (S.unique (names prob))
diff --git a/Jukebox/Toolbox.hs b/Jukebox/Toolbox.hs
deleted file mode 100644
--- a/Jukebox/Toolbox.hs
+++ /dev/null
@@ -1,251 +0,0 @@
-module Jukebox.Toolbox where
-
-import Jukebox.Options
-import qualified Data.ByteString.Char8 as BS
-import qualified Data.ByteString.Lazy.Char8 as BSL
-import Jukebox.Form
-import Jukebox.Name
-import qualified Jukebox.NameMap as NameMap
-import Jukebox.TPTP.Print
-import Control.Monad
-import Control.Applicative
-import Jukebox.Clausify
-import Jukebox.TPTP.ParseProblem
-import Jukebox.Monotonox.Monotonicity hiding (guards)
-import Jukebox.Monotonox.ToFOF
-import System.Exit
-import System.IO
-import Jukebox.TPTP.FindFile
-import Text.PrettyPrint.HughesPJ
-import Jukebox.GuessModel
-import Jukebox.InferTypes
-import Jukebox.TPTP.Parsec hiding (Error)
-import qualified Jukebox.TPTP.Parsec as Parser
-import Jukebox.TPTP.ClauseParser
-import Jukebox.TPTP.Lexer hiding (Error, name, Normal)
-import qualified Jukebox.TPTP.Lexer as Lexer
-
-data GlobalFlags =
-  GlobalFlags {
-    quiet :: Bool }
-  deriving Show
-
-globalFlags :: OptionParser GlobalFlags
-globalFlags =
-  inGroup "Global options" $
-  GlobalFlags <$>
-    bool "quiet"
-      ["Do not print any informational output.",
-       "Default: (off)"]
-
-(=>>=) :: (Monad m, Applicative f) => f (a -> m b) -> f (b -> m c) -> f (a -> m c)
-f =>>= g = (>=>) <$> f <*> g
-infixl 1 =>>= -- same as >=>
-
-(=>>) :: (Monad m, Applicative f) => f (m a) -> f (m b) -> f (m b)
-x =>> y = (>>) <$> x <*> y
-infixl 1 =>> -- same as >>
-
-greetingBox :: Tool -> OptionParser (IO ())
-greetingBox t = greetingBoxIO t <$> globalFlags
-
-greetingBoxIO :: Tool -> GlobalFlags -> IO ()
-greetingBoxIO t GlobalFlags{quiet = quiet} =
-  unless quiet $ hPutStrLn stderr (greeting t)
-
-allFilesBox :: OptionParser ((FilePath -> IO ()) -> IO ())
-allFilesBox = flip allFiles <$> filenames
-
-allFiles :: (FilePath -> IO ()) -> [FilePath] -> IO ()
-allFiles _ [] = do
-  hPutStrLn stderr "No input files specified! Try --help."
-  exitWith (ExitFailure 1)
-allFiles f xs = mapM_ f xs
-
-parseProblemBox :: OptionParser (FilePath -> IO (Problem Form))
-parseProblemBox = parseProblemIO <$> findFileFlags
-
-parseProblemIO :: [FilePath] -> FilePath -> IO (Problem Form)
-parseProblemIO dirs f = do
-  r <- parseProblem dirs f
-  case r of
-    Left err -> do
-      hPutStrLn stderr err
-      exitWith (ExitFailure 1)
-    Right x -> return x
-
-withString :: (Symbolic a, Pretty a) => String -> (Problem Form -> IO (Problem a)) -> String -> IO String
-withString kind f x = do
-  let errorAt (UserState _ (At (Lexer.Pos l c) _)) err =
-        error $ "At line " ++ show l ++ ", column " ++ show c ++ ": " ++ err
-  case run_ (section (const True) <* eof)
-            (UserState initialState (scan (BSL.pack x))) of
-    Ok (UserState (MkState p _ _ _ _ n) (At _ (Cons Eof _))) Nothing -> do
-      let prob = close_ n (return (reverse p))
-      res <- f prob
-      return (render (prettyProblem kind Normal res))
-    Ok s@(UserState _ (At _ (Cons Eof _))) (Just _) ->
-      errorAt s "can't handle include files"
-    Ok s _ ->
-      errorAt s "lexical error"
-    Parser.Error s msg -> errorAt s $ "parse error: " ++ msg
-    Expected s exp -> errorAt s $ "parse error: expected " ++ show exp
-
-encodeString :: String -> IO String
-encodeString = withString "fof" f
-  where
-    f = toFofIO globals (return . clausify clFlags) (tags False)
-    globals = GlobalFlags { quiet = True }
-    clFlags = ClausifyFlags { splitting = False }
-
-clausifyBox :: OptionParser (Problem Form -> IO CNF)
-clausifyBox = clausifyIO <$> globalFlags <*> clausifyFlags
-
-clausifyIO :: GlobalFlags -> ClausifyFlags -> Problem Form -> IO CNF
-clausifyIO globals flags prob = do
-  unless (quiet globals) $ hPutStrLn stderr "Clausifying problem..."
-  return $! clausify flags prob
-
-toFofBox :: OptionParser (Problem Form -> IO (Problem Form))
-toFofBox = toFofIO <$> globalFlags <*> clausifyBox <*> schemeBox
-
-oneConjectureBox :: OptionParser (CNF -> IO (Problem Clause))
-oneConjectureBox = pure oneConjecture
-
-oneConjecture :: CNF -> IO (Problem Clause)
-oneConjecture cnf = closedIO (close cnf f)
-  where f (Obligs cs [cs'] _ _) = return (return (cs ++ cs'))
-        f _ = return $ do
-          hPutStrLn stderr "Error: more than one conjecture found in input problem"
-          exitWith (ExitFailure 1)
-
-toFofIO :: GlobalFlags -> (Problem Form -> IO CNF) -> Scheme -> Problem Form -> IO (Problem Form)
-toFofIO globals clausify scheme f = do
-  cs <- clausify f >>= oneConjecture
-  unless (quiet globals) $ hPutStrLn stderr "Monotonicity analysis..."
-  m <- monotone (map what (open cs))
-  let isMonotone ty =
-        case NameMap.lookup (name ty) m of
-          Just (_ ::: Nothing) -> False
-          Just (_ ::: Just _) -> True
-          Nothing  -> True -- can happen if clausifier removed all clauses about a type
-  return (translate scheme isMonotone f)
-
-schemeBox :: OptionParser Scheme
-schemeBox =
-  choose <$>
-  flag "encoding"
-    ["Which type encoding to use.",
-     "Default: --encoding guards"]
-    "guards"
-    (argOption ["guards", "tags"])
-  <*> tagsFlags
-  where choose "guards" flags = guards
-        choose "tags" flags = tags flags
-
-monotonicityBox :: OptionParser (Problem Clause -> IO String)
-monotonicityBox = monotonicity <$> globalFlags
-
-monotonicity :: GlobalFlags -> Problem Clause -> IO String
-monotonicity globals cs = do
-  unless (quiet globals) $ hPutStrLn stderr "Monotonicity analysis..."
-  m <- monotone (map what (open cs))
-  let info (ty ::: Nothing) = [BS.unpack (baseName ty) ++ ": not monotone"]
-      info (ty ::: Just m) =
-        [prettyShow ty ++ ": monotone"] ++
-        concat
-        [ case ext of
-             CopyExtend -> []
-             TrueExtend -> ["  " ++ BS.unpack (baseName p) ++ " true-extended"]
-             FalseExtend -> ["  " ++ BS.unpack (baseName p) ++ " false-extended"]
-        | p ::: ext <- NameMap.toList m ]
-
-  return (unlines (concat (map info (NameMap.toList m))))
-
-annotateMonotonicityBox :: OptionParser (Problem Clause -> IO (Problem Clause))
-annotateMonotonicityBox = (\globals x -> do
-  unless (quiet globals) $ putStrLn "Monotonicity analysis..."
-  annotateMonotonicity x) <$> globalFlags
-
-prettyPrintBox :: (Symbolic a, Pretty a) => OptionParser (Problem a -> IO ())
-prettyPrintBox = prettyFormIO <$> globalFlags <*> writeFileBox
-
-prettyFormIO :: (Symbolic a, Pretty a) => GlobalFlags -> (String -> IO ()) -> Problem a -> IO ()
-prettyFormIO globals write prob
-  | isFof (open prob) = prettyPrintIO globals "fof" write prob
-  | otherwise = prettyPrintIO globals "tff" write prob
-
-prettyClauseBox :: OptionParser (Problem Clause -> IO ())
-prettyClauseBox = f <$> globalFlags <*> writeFileBox
-  where
-    f globals write cs
-      | isFof (open cs) = prettyPrintIO globals "cnf" write cs
-      | otherwise = prettyPrintIO globals "tff" write (fmap (map (fmap toForm)) cs)
-
-prettyPrintIO :: (Symbolic a, Pretty a) => GlobalFlags -> String -> (String -> IO ()) -> Problem a -> IO ()
-prettyPrintIO globals kind write prob = do
-  unless (quiet globals) $ hPutStrLn stderr "Writing output..."
-  write (render (prettyProblem kind Normal prob) ++ "\n")
-
-writeFileBox :: OptionParser (String -> IO ())
-writeFileBox =
-  flag "output"
-    ["Where to write the output.",
-     "Default: stdout"]
-    putStr
-    (fmap myWriteFile argFile)
-  where myWriteFile "/dev/null" _ = return ()
-        myWriteFile file contents = writeFile file contents
-
-guessModelBox :: OptionParser (Problem Form -> IO (Problem Form))
-guessModelBox = guessModelIO <$> expansive <*> universe
-  where universe = choose <$>
-                   flag "universe"
-                   ["Which universe to find the model in.",
-                    "Default: peano"]
-                   "peano"
-                   (argOption ["peano", "trees"])
-        choose "peano" = Peano
-        choose "trees" = Trees
-        expansive = manyFlags "expansive"
-                    ["Allow a function to construct 'new' terms in its base base."]
-                    (arg "<function>" "expected a function name" Just)
-
-guessModelIO :: [String] -> Universe -> Problem Form -> IO (Problem Form)
-guessModelIO expansive univ prob = return (guessModel expansive univ prob)
-
-allObligsBox :: OptionParser ((Problem Clause -> IO Answer) -> Closed Obligs -> IO ())
-allObligsBox = pure allObligsIO
-
-allObligsIO solve obligs = loop 1 conjectures
-  where Obligs { axioms = axioms, conjectures = conjectures,
-                 satisfiable = satisfiable, unsatisfiable = unsatisfiable } =
-          open obligs
-
-        loop _ [] = result unsatisfiable
-        loop i (c:cs) = do
-          when multi $ putStrLn $ "Part " ++ part i
-          answer <- solve (close_ obligs (return (axioms ++ c)))
-          when multi $ putStrLn $ "+++ PARTIAL (" ++ part i ++ "): " ++ show answer
-          case answer of
-            Satisfiable -> result satisfiable
-            Unsatisfiable -> loop (i+1) cs
-            NoAnswer x -> result (show x)
-        multi = length conjectures > 1
-        part i = show i ++ "/" ++ show (length conjectures)
-        result x = putStrLn ("+++ RESULT: " ++ x)
-
-inferBox :: OptionParser (Problem Clause -> IO (Problem Clause, Type -> Type))
-inferBox = (\globals prob -> do
-  unless (quiet globals) $ putStrLn "Inferring types..."
-  let prob' = close prob inferTypes
-  return (fmap fst prob', snd (open prob'))) <$> globalFlags
-
-printInferredBox :: OptionParser ((Problem Clause, Type -> Type) -> IO (Problem Clause))
-printInferredBox = pure $ \(prob, rep) -> do
-  forM_ (types (open prob)) $ \ty ->
-    putStrLn $ show ty ++ " => " ++ show (rep ty)
-  return prob
-
-equinoxBox :: OptionParser (Problem Clause -> IO Answer)
-equinoxBox = pure (\f -> return (NoAnswer GaveUp)) -- A highly sophisticated proof method. We are sure to win CASC! :)
diff --git a/Jukebox/UnionFind.hs b/Jukebox/UnionFind.hs
deleted file mode 100644
--- a/Jukebox/UnionFind.hs
+++ /dev/null
@@ -1,76 +0,0 @@
-module Jukebox.UnionFind(UF, Replacement((:>)), (=:=), rep, evalUF, execUF, runUF, S, isRep, initial, reps) where
-
-import Prelude hiding (min)
-import Control.Monad.State.Strict
-import Data.Hashable
-import Jukebox.Map(Map)
-import qualified Jukebox.Map as Map
-
-type S a = Map a a
-type UF a = State (S a)
-data Replacement a = a :> a
-
-runUF :: S a -> UF a b -> (b, S a)
-runUF s m = runState m s
-
-evalUF :: S a -> UF a b -> b
-evalUF s m = fst (runUF s m)
-
-execUF :: S a -> UF a b -> S a
-execUF s m = snd (runUF s m)
-
-initial :: S a
-initial = Map.empty
-
-(=:=) :: (Hashable a, Ord a) => a -> a -> UF a (Maybe (Replacement a))
-s =:= t | s == t = return Nothing
-s =:= t = do
-  rs <- rep s
-  rt <- rep t
-  case rs `compare` rt of
-    EQ -> return Nothing
-    LT -> do
-      modify (Map.insert rt rs)
-      return (Just (rt :> rs))
-    GT -> do
-      modify (Map.insert rs rt)
-      return (Just (rs :> rt))
-
-{-# INLINE rep #-}
-rep :: (Hashable a, Ord a) => a -> UF a a
-rep s = do
-  m <- get
-  case Map.lookup s m of
-    Nothing -> return s
-    Just t -> do
-      u <- rep t
-      when (t /= u) $ modify (Map.insert s u)
-      return u
-      -- case Map.lookup t m of
-      --   Nothing -> return t
-      --   Just u -> do
-      --     v <- rep' t u
-      --     modify (Map.insert s v)
-      --     return v
-
-reps :: (Hashable a, Ord a) => UF a (a -> a)
-reps = do
-  s <- get
-  return (\x -> evalUF s (rep x))
-
--- rep' :: (Hashable a, Ord a) => a -> a -> UF a a
--- rep' s t = do
---   m <- get
---   case Map.lookup t m of
---     Nothing -> do
---       modify (Map.insert s t)
---       return t
---     Just u -> do
---       v <- rep' t u
---       modify (Map.insert s v)
---       return v
-
-isRep :: (Hashable a, Ord a) => a -> UF a Bool
-isRep t = do
-  t' <- rep t
-  return (t == t')
diff --git a/Jukebox/Utils.hs b/Jukebox/Utils.hs
deleted file mode 100644
--- a/Jukebox/Utils.hs
+++ /dev/null
@@ -1,38 +0,0 @@
-{-# LANGUAGE TupleSections #-}
-module Jukebox.Utils where
-
-import Data.List
-import qualified Jukebox.Seq as Seq
-import qualified Data.HashSet as Set
-import Data.Hashable
-import System.Process
-import qualified Data.ByteString.Char8 as BS
-import System.IO
-import System.Exit
-import Control.Applicative
-import Control.Concurrent
-
-usort :: Ord a => [a] -> [a]
-usort = map head . group . sort
-
-merge :: Ord a => [a] -> [a] -> [a]
-merge [] ys = ys
-merge xs [] = xs
-merge (x:xs) (y:ys) =
-  case x `compare` y of
-    LT -> x:merge xs (y:ys)
-    EQ -> x:merge xs ys
-    GT -> y:merge (x:xs) ys
-
-nub :: (Seq.List f, Ord a, Hashable a) => f a -> [a]
-nub = Set.toList . Set.fromList . Seq.toList
-
-popen :: FilePath -> [String] -> BS.ByteString -> IO (ExitCode, BS.ByteString)
-popen prog args inp = do
-  (stdin, stdout, stderr_, pid) <- runInteractiveProcess prog args Nothing Nothing
-  forkIO $ hGetContents stderr_ >>= hPutStr stderr
-  BS.hPutStr stdin inp
-  hFlush stdin
-  hClose stdin
-  code <- waitForProcess pid
-  fmap (code,) (BS.hGetContents stdout) <* hClose stdout
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2009-2014, Nick Smallbone, Koen Claessen, Ann Lillieström
+Copyright (c) 2009-2016, Nick Smallbone, Koen Claessen, Ann Lillieström
 
 All rights reserved.
 
diff --git a/Main.hs b/Main.hs
deleted file mode 100644
--- a/Main.hs
+++ /dev/null
@@ -1,87 +0,0 @@
-module Main where
-
-import Control.Monad
-import Jukebox.Options
-import Control.Applicative
-import Data.Monoid
-import Jukebox.Toolbox
-
-tools = mconcat [fof, cnf, monotonox, guessmodel]
-
-fof = tool info pipeline
-  where
-    info = Tool "fof" "Jukebox TFF-to-FOF translator" "1"
-                "Translate from TFF (typed) to FOF (untyped)"
-    pipeline =
-      greetingBox info =>>
-      allFilesBox <*>
-        (parseProblemBox =>>=
-         toFofBox =>>=
-         prettyPrintBox)
-
-monotonox = tool info pipeline
-  where
-    info = Tool "monotonox" "Monotonox" "1"
-                "Monotonicity analysis"
-    pipeline =
-      greetingBox info =>>
-      allFilesBox <*>
-        (parseProblemBox =>>=
-         clausifyBox =>>=
-         oneConjectureBox =>>=
-         monotonicityBox =>>=
-         writeFileBox)
-
-cnf = tool info pipeline
-  where
-    info = Tool "cnf" "Jukebox clausifier" "1"
-                "Clausify a problem"
-    pipeline =
-      greetingBox info =>>
-      allFilesBox <*>
-        (parseProblemBox =>>=
-         clausifyBox =>>=
-         oneConjectureBox =>>=
-         prettyClauseBox)
-
-justparser = tool info pipeline
-  where
-    info = Tool "parser" "Parser" "1"
-                "Just parse the problem"
-    pipeline =
-      greetingBox info =>>
-      allFilesBox <*>
-        (parseProblemBox =>>=
-         clausifyBox =>>=
-         oneConjectureBox =>>=
-         inferBox =>>=
-         printInferredBox =>>=
-         annotateMonotonicityBox =>>=
-         prettyPrintBox)
-
-guessmodel = tool info pipeline
-  where
-    info = Tool "guessmodel" "Infinite model guesser" "1"
-                "Guess an infinite model"
-    pipeline =
-      greetingBox info =>>
-      allFilesBox <*>
-        (parseProblemBox =>>=
-         guessModelBox =>>=
-         prettyPrintBox)
-
-equinox = tool info pipeline
-  where
-    info = Tool "equinox" "Equinox" "7"
-                "Prove a first-order problem"
-    pipeline =
-      greetingBox info =>>
-      allFilesBox <*>
-        (parseProblemBox =>>=
-         clausifyBox =>>=
-         allObligsBox <*> equinoxBox)
-
-jukebox = Tool "jukebox" "Jukebox" "1"
-               "A first-order logic toolbox"
-
-main = join (parseCommandLine jukebox tools)
diff --git a/dist/build/Jukebox/TPTP/Lexer.hs b/dist/build/Jukebox/TPTP/Lexer.hs
--- a/dist/build/Jukebox/TPTP/Lexer.hs
+++ b/dist/build/Jukebox/TPTP/Lexer.hs
@@ -1,6 +1,6 @@
 {-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-missing-signatures #-}
 {-# LANGUAGE CPP,MagicHash #-}
-{-# LINE 4 "Jukebox/TPTP/Lexer.x" #-}
+{-# LINE 4 "src/Jukebox/TPTP/Lexer.x" #-}
 
 {-# OPTIONS_GHC -O2 -fno-warn-deprecated-flags #-}
 {-# LANGUAGE BangPatterns #-}
@@ -14,9 +14,6 @@
   TokenStream(..),
   Contents(..)) where
 
-import qualified Data.ByteString.Char8 as BS
-import qualified Data.ByteString.Lazy.Char8 as BSL
-import Data.ByteString.Lazy.Internal
 import Data.Word
 import Data.Char
 
@@ -51,13 +48,13 @@
 alex_deflt = AlexA# "\xff\xff\x2e\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x16\x00\x16\x00\x18\x00\x18\x00\x1a\x00\x1a\x00\x1f\x00\x1f\x00\x28\x00\x28\x00\x2d\x00\x2d\x00\x2e\x00\xff\xff\x2e\x00\x2e\x00\x30\x00\x2f\x00\x2f\x00\x30\x00\x36\x00\xff\xff\xff\xff\x36\x00\x36\x00\x04\x00\xff\xff\xff\xff\x04\x00\x04\x00\x2e\x00\x3d\x00\x3c\x00\x3c\x00\x3d\x00\xff\xff\xff\xff\xff\xff\xff\xff\x3f\x00\x3e\x00\xff\xff\x3f\x00\x3e\x00\x3f\x00\x3e\x00\xff\xff\x3f\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"#
 
 alex_accept = listArray (0::Int,287) [AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccNone,AlexAccSkip,AlexAccSkip,AlexAccSkip,AlexAccSkip,AlexAcc (alex_action_3),AlexAcc (alex_action_4),AlexAcc (alex_action_5),AlexAcc (alex_action_6),AlexAcc (alex_action_7),AlexAcc (alex_action_8),AlexAcc (alex_action_9),AlexAcc (alex_action_10),AlexAcc (alex_action_11),AlexAcc (alex_action_12),AlexAcc (alex_action_13),AlexAcc (alex_action_14),AlexAcc (alex_action_15),AlexAcc (alex_action_16),AlexAcc (alex_action_17),AlexAcc (alex_action_18),AlexAcc (alex_action_19),AlexAcc (alex_action_20),AlexAcc (alex_action_21),AlexAcc (alex_action_22),AlexAcc (alex_action_23),AlexAcc (alex_action_24),AlexAcc (alex_action_25),AlexAcc (alex_action_26),AlexAcc (alex_action_27),AlexAcc (alex_action_28),AlexAcc (alex_action_29),AlexAcc (alex_action_29),AlexAcc (alex_action_30),AlexAcc (alex_action_30),AlexAcc (alex_action_31),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_32),AlexAcc (alex_action_33),AlexAcc (alex_action_34),AlexAcc (alex_action_35),AlexAccPred  (alex_action_36) (alexRightContext 57)(AlexAccNone),AlexAccPred  (alex_action_36) (alexRightContext 57)(AlexAccNone),AlexAcc (alex_action_37),AlexAcc (alex_action_38),AlexAcc (alex_action_39),AlexAcc (alex_action_40),AlexAcc (alex_action_41),AlexAcc (alex_action_42),AlexAcc (alex_action_43),AlexAcc (alex_action_44),AlexAcc (alex_action_45),AlexAcc (alex_action_46),AlexAcc (alex_action_47),AlexAcc (alex_action_48),AlexAcc (alex_action_49),AlexAcc (alex_action_50),AlexAcc (alex_action_51),AlexAcc (alex_action_52),AlexAcc (alex_action_53),AlexAcc (alex_action_54),AlexAcc (alex_action_55),AlexAcc (alex_action_56),AlexAcc (alex_action_57),AlexAcc (alex_action_58),AlexAcc (alex_action_59),AlexAcc (alex_action_60),AlexAcc (alex_action_61),AlexAcc (alex_action_62),AlexAcc (alex_action_63),AlexAcc (alex_action_64),AlexAcc (alex_action_65),AlexAcc (alex_action_66),AlexAcc (alex_action_67),AlexAcc (alex_action_68),AlexAcc (alex_action_69),AlexAcc (alex_action_70),AlexAcc (alex_action_71)]
-{-# LINE 95 "Jukebox/TPTP/Lexer.x" #-}
+{-# LINE 92 "src/Jukebox/TPTP/Lexer.x" #-}
 
 data Pos = Pos {-# UNPACK #-} !Word {-# UNPACK #-} !Word deriving Show
-data Token = Atom { keyword :: !Keyword, name :: !BS.ByteString }
+data Token = Atom { keyword :: !Keyword, tokenName :: !String }
            | Defined { defined :: !Defined  }
-           | Var { name :: !BS.ByteString }
-           | DistinctObject { name :: !BS.ByteString }
+           | Var { tokenName :: !String }
+           | DistinctObject { tokenName :: !String }
            | Number { value :: !Integer }
            | Punct { kind :: !Punct }
            | Eof
@@ -114,51 +111,40 @@
       Exists -> "?"; Let -> ":="; Colon -> ":"; Times -> "*"; Plus -> "+";
       FunArrow -> ">"; Lambda -> "^"; Apply -> "@"; ForAllLam -> "!!";
       ExistsLam -> "??"; Some -> "@+"; The -> "@-"; Subtype -> "<<";
-      SequentArrow -> "-->"; DependentProduct -> "!>"; DependentSum -> "?*" }
+      SequentArrow -> "-->"; DependentProduct -> "!>"; DependentSum -> "?*";
+      LetTerm -> ":-" }
 
 p x = const (Punct x)
 k x = Atom x . copy
 d x = const (Defined x)
 
-copy :: BS.ByteString -> BS.ByteString
-copy = id -- could change to a string interning function later
-
-unquote :: BS.ByteString -> BS.ByteString
-unquote x =
-  case BSL.toChunks (BSL.tail (unquote' x)) of
-    [] -> BS.empty
-    [x] -> copy x
-    xs -> BS.concat xs
+copy :: String -> String
+copy = id
 
-unquote' :: BS.ByteString -> BSL.ByteString
-unquote' x | BS.null z = chunk (BS.init y) Empty
-           | otherwise = chunk y (BS.index z 1 `BSL.cons'` unquote' (BS.drop 2 z))
-           where (y, z) = BS.break (== '\\') x
+unquote :: String -> String
+unquote (_:x)
+  | null z = init y
+  | otherwise = y ++ [z !! 1] ++ unquote (drop 2 z)
+  where (y, z) = break (== '\\') x
     
-readNumber :: BS.ByteString -> Integer
-readNumber x | BS.null r = n
-  where Just (n, r) = BS.readInteger x
-
 -- The main scanner function, heavily modified from Alex's posn-bytestring wrapper.
 
 data TokenStream = At {-# UNPACK #-} !Pos !Contents
 data Contents = Cons !Token TokenStream
 
-scan xs = go (Input (Pos 1 1) '\n' BS.empty xs)
-  where go inp@(Input pos _ x xs) =
+scan xs = go (Input (Pos 1 1) '\n' xs)
+  where go inp@(Input pos _ xs) =
           case alexScan inp 0 of
                 AlexEOF -> let t = At pos (Cons Eof t) in t
                 AlexError _ -> let t = At pos (Cons Error t) in t
-                AlexSkip  inp' len -> go inp'
+                AlexSkip  inp' _ -> go inp'
                 AlexToken inp' len act ->
-                  let token | len <= BS.length x = BS.take len x
-                            | otherwise = BS.concat (BSL.toChunks (BSL.take (fromIntegral len) (chunk x xs)))
-                  in At pos (act token `Cons` go inp')
+                  At pos (act (take len xs) `Cons` go inp')
 
-data AlexInput = Input {-# UNPACK #-} !Pos {-# UNPACK #-} !Char {-# UNPACK #-} !BS.ByteString BSL.ByteString
+data AlexInput = Input {-# UNPACK #-} !Pos {-# UNPACK #-} !Char String
 
 alexInputPrevChar :: AlexInput -> Char
-alexInputPrevChar (Input p c x xs) = c
+alexInputPrevChar (Input _ c _) = c
 
 {-# INLINE alexGetByte #-}
 alexGetByte :: AlexInput -> Maybe (Word8,AlexInput)
@@ -166,19 +152,14 @@
   where f (c, i') = (fromIntegral (ord c), i')
 {-# INLINE alexGetChar #-}
 alexGetChar :: AlexInput -> Maybe (Char,AlexInput)
-alexGetChar (Input p _ x xs) | not (BS.null x) = getCharNonEmpty p x xs
-alexGetChar (Input p _ _ (Chunk x xs)) = getCharNonEmpty p x xs
-alexGetChar (Input p _ _ Empty) = Nothing
-{-# INLINE getCharNonEmpty #-}
-getCharNonEmpty p x xs =
-  let !c = BS.head x
-      !next = Input (advance p c) c (BS.tail x) xs
-  in Just (c, next)
+alexGetChar (Input p _ (x:xs)) =
+  Just (x, Input (advance p x) x xs)
+alexGetChar _ = Nothing
 
 {-# INLINE advance #-}
 advance :: Pos -> Char -> Pos
 advance (Pos l c) '\t' = Pos  l    (c+8 - (c-1) `mod` 8)
-advance (Pos l c) '\n' = Pos (l+1) 1
+advance (Pos l _) '\n' = Pos (l+1) 1
 advance (Pos l c) _    = Pos  l    (c+1)
 
 alex_action_3 =  k Thf 
@@ -214,7 +195,7 @@
 alex_action_33 =  Atom Normal . unquote 
 alex_action_34 =  Var . copy 
 alex_action_35 =  DistinctObject . unquote 
-alex_action_36 =  Number . readNumber 
+alex_action_36 =  Number . read 
 alex_action_37 =  p LParen 
 alex_action_38 =  p RParen 
 alex_action_39 =  p LBrack 
diff --git a/executable/Main.hs b/executable/Main.hs
new file mode 100644
--- /dev/null
+++ b/executable/Main.hs
@@ -0,0 +1,59 @@
+module Main where
+
+import Control.Monad
+import Jukebox.Options
+import Jukebox.Toolbox
+
+tools = mconcat [fof, cnf, monotonox, guessmodel]
+
+fof = tool info pipeline
+  where
+    info = Tool "fof" "Jukebox TFF-to-FOF translator" "1"
+                "Translate from TFF (typed) to FOF (untyped)"
+    pipeline =
+      greetingBox info =>>
+      allFilesBox <*>
+        (parseProblemBox =>>=
+         toFofBox =>>=
+         prettyPrintProblemBox)
+
+monotonox = tool info pipeline
+  where
+    info = Tool "monotonox" "Monotonox" "1"
+                "Monotonicity analysis"
+    pipeline =
+      greetingBox info =>>
+      allFilesBox <*>
+        (parseProblemBox =>>=
+         clausifyBox =>>=
+         oneConjectureBox =>>=
+         monotonicityBox =>>=
+         writeFileBox)
+
+cnf = tool info pipeline
+  where
+    info = Tool "cnf" "Jukebox clausifier" "1"
+                "Clausify a problem"
+    pipeline =
+      greetingBox info =>>
+      allFilesBox <*>
+        (parseProblemBox =>>=
+         clausifyBox =>>=
+         oneConjectureBox =>>=
+         prettyPrintClausesBox)
+
+guessmodel = tool info pipeline
+  where
+    info = Tool "guessmodel" "Infinite model guesser" "1"
+                "Guess an infinite model"
+    pipeline =
+      greetingBox info =>>
+      allFilesBox <*>
+        (parseProblemBox =>>=
+         guessModelBox =>>=
+         prettyPrintProblemBox)
+
+jukebox = Tool "jukebox" "Jukebox" "1"
+               "A first-order logic toolbox"
+
+main = join (parseCommandLine jukebox tools)
diff --git a/jukebox.cabal b/jukebox.cabal
--- a/jukebox.cabal
+++ b/jukebox.cabal
@@ -1,10 +1,10 @@
 Name: jukebox
-Version: 0.1.6
+Version: 0.2
 Cabal-version: >= 1.8
 Build-type: Simple
 Author: Nick Smallbone
 Maintainer: nicsma@chalmers.se
-Copyright: 2009-2014 Nick Smallbone, Koen Claessen, Ann Lillieström
+Copyright: 2009-2016 Nick Smallbone, Koen Claessen, Ann Lillieström
 
 Category:            Logic
 
@@ -23,47 +23,41 @@
   location: https://github.com/nick8325/jukebox
 
 Library
-  Build-depends: bytestring, base >= 4 && < 5, array, mtl, directory,
-    filepath, pretty, hashable, minisat,
-    binary, unordered-containers, process, containers
+  Build-depends: base >= 4 && < 5, array, transformers, directory,
+    filepath, pretty, minisat, symbol, dlist,
+    binary, unordered-containers, process, containers, uglymemo
+  ghc-options: -W -fno-warn-incomplete-patterns
   Build-tools: alex
-  Ghc-options: -funfolding-use-threshold=500
+  Hs-source-dirs: src
+  include-dirs: src
   Exposed-modules:
     Jukebox.Clausify
     Jukebox.Form
     Jukebox.GuessModel
     Jukebox.HighSat
     Jukebox.InferTypes
-    Jukebox.Map
     Jukebox.Monotonox.Monotonicity
     Jukebox.Monotonox.ToFOF
     Jukebox.Name
-    Jukebox.NameMap
     Jukebox.Options
-    Jukebox.ProgressBar
     Jukebox.Provers.E
     Jukebox.Provers.SPASS
     Jukebox.Sat3
     Jukebox.SatEq
     Jukebox.Sat
     Jukebox.SatMin
-    Jukebox.Seq
     Jukebox.Toolbox
-    Jukebox.TPTP.ClauseParser
+    Jukebox.TPTP.Parse.Core
     Jukebox.TPTP.FindFile
     Jukebox.TPTP.Lexer
     Jukebox.TPTP.Parsec
-    Jukebox.TPTP.ParseProblem
+    Jukebox.TPTP.Parse
     Jukebox.TPTP.ParseSnippet
     Jukebox.TPTP.Print
     Jukebox.UnionFind
     Jukebox.Utils
 
 Executable jukebox
-  Main-is: Main.hs
-  Build-depends: bytestring, base >= 4 && < 5, array, mtl, directory,
-    filepath, pretty, hashable, minisat,
-    binary, unordered-containers, process, containers,
-    jukebox
-  Build-tools: alex
-  Ghc-options: -funfolding-use-threshold=500
+  Main-is: executable/Main.hs
+  Build-depends: base >= 4 && < 5, jukebox
+  ghc-options: -W -fno-warn-incomplete-patterns
diff --git a/src/Jukebox/Clausify.hs b/src/Jukebox/Clausify.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/Clausify.hs
@@ -0,0 +1,432 @@
+{-# LANGUAGE TypeOperators, BangPatterns #-}
+module Jukebox.Clausify where
+
+import Jukebox.Form hiding (run)
+import qualified Jukebox.Form as Form
+import Jukebox.Name
+import Data.List( maximumBy, sortBy, partition )
+import Data.Ord
+import Control.Monad
+import Control.Monad.Trans.Class
+import Control.Monad.Trans.Reader
+import Jukebox.Utils
+import Jukebox.Options
+import qualified Data.Set as Set
+import Data.Set(Set)
+
+newtype ClausifyFlags = ClausifyFlags { splitting :: Bool } deriving Show
+
+clausifyFlags =
+  inGroup "Clausifier options" $
+  ClausifyFlags <$>
+    bool "split"
+      ["Split the conjecture into several sub-conjectures.",
+       "Default: (off)"]
+
+----------------------------------------------------------------------
+-- clausify
+
+clausify :: ClausifyFlags -> Problem Form -> CNF
+clausify flags inps = Form.run inps (run . clausifyInputs [] [])
+ where
+  clausifyInputs theory obligs [] =
+    do return (toCNF (reverse theory) (reverse obligs))
+  
+  clausifyInputs theory obligs (inp:inps) | kind inp == Axiom =
+    do cs <- clausForm (tag inp) (what inp)
+       clausifyInputs (cs ++ theory) obligs inps
+
+  clausifyInputs theory obligs (inp:inps) | kind inp `elem` [Conjecture, Question] =
+    do clausifyObligs theory obligs (tag inp) (split' (what inp)) inps
+
+  clausifyObligs theory obligs _ [] inps =
+    do clausifyInputs theory obligs inps
+  
+  clausifyObligs theory obligs s (a:as) inps =
+    do cs <- clausForm s (nt a)
+       clausifyObligs theory (cs:obligs) s as inps
+
+  split' a | splitting flags = if null split_a then [true] else split_a
+    where split_a = split a
+  split' a                   = [a]
+
+split :: Form -> [Form]
+split p =
+  case positive p of
+    ForAll (Bind xs p) ->
+      [ ForAll (Bind xs p') | p' <- split p ]
+    
+    And ps -> concatMap split ps
+    
+    p `Equiv` q ->
+      split (nt p \/ q) ++ split (p \/ nt q)
+
+    Or ps ->
+      snd $
+      maximumBy (comparing fst)
+      [ (siz q, [ Or (q':qs) | q' <- sq ])
+      | (q,qs) <- select ps
+      , let sq = split q
+      ]
+
+    _ ->
+      [p]
+ where
+  select []     = []
+  select (x:xs) = (x,xs) : [ (y,x:ys) | (y,ys) <- select xs ]
+  
+  siz (And ps)            = length ps
+  siz (ForAll (Bind _ p)) = siz p
+  siz (_ `Equiv` _)       = 2
+  siz _                   = 0
+
+{-  
+    Or ps | length ps > 0 && n > 0 ->
+      [ Or (p':ps') | p' <- split p ]
+     where
+      pns = [(p,siz p) | p <- ps]
+      ((p,n),pns') = getMax (head pns) [] (tail pns)
+      ps' = [ p' | (p',_) <- pns' ]
+    
+  getMax pn@(p,n) pns [] = (pn,pns)
+  getMax pn@(p,n) pns (qm@(q,m):qms)
+    | m > n     = getMax qm (pn:pns) qms
+    | otherwise = getMax pn (qm:pns) qms
+-}
+
+----------------------------------------------------------------------
+-- core clausification algorithm
+
+clausForm :: String -> Form -> M [Input Clause]
+clausForm s p =
+  withName s $
+    do miniscoped      <- miniscope . check . simplify         . check $ p
+       noEquivPs       <- removeEquiv                          . check $ miniscoped
+       noExistsPs      <- mapM removeExists                    . check $ noEquivPs
+       noExpensiveOrPs <- fmap concat . mapM removeExpensiveOr . check $ noExistsPs
+       noForAllPs      <- lift . mapM uniqueNames              . check $ noExpensiveOrPs
+       let !cnf_        = concatMap cnf                        . check $ noForAllPs
+           !simp        = simplifyCNF                          . check $ cnf_
+           cs           = fmap clause                                  $ simp
+           inps         = [ Input (s ++ i) Axiom c
+                          | (c, i) <- zip cs ("":
+                                        [ '_':show i | i <- [1..] ]) ]
+       return $! force . check                                         $ inps
+
+----------------------------------------------------------------------
+-- miniscoping
+miniscope :: Form -> M Form
+miniscope t@Literal{} = return t
+miniscope (Not f) = fmap Not (miniscope f)
+miniscope (And fs) = fmap And (mapM miniscope fs)
+miniscope (Or fs) = fmap Or (mapM miniscope fs)
+miniscope (Equiv f g) = liftM2 Equiv (miniscope f) (miniscope g)
+miniscope (ForAll (Bind xs f)) = miniscope f >>= forAll xs
+miniscope (Exists (Bind xs f)) = miniscope f >>= forAll xs . nt >>= return . nt
+
+forAll :: Set Variable -> Form -> M Form
+forAll xs a | Set.null xs = return a
+forAll xs a =
+  case positive a of
+    And as ->
+      fmap And (mapM (forAll xs) as)
+    
+    ForAll (Bind ys a)
+      | Set.null m -> return (ForAll (Bind ys a))
+      | otherwise -> fmap (forAll' ys) (forAll m a)
+      where m = xs Set.\\ ys
+            forAll' vs (ForAll (Bind vs' t)) = ForAll (Bind (vs `Set.union` vs') t)
+            forAll' vs t = ForAll (Bind vs t)
+
+    Or as -> forAllOr xs [ (a, free a) | a <- as ]
+
+    _ -> return (ForAll (Bind xs a))
+
+forAllOr :: Set Variable -> [(Form, Set Variable)] -> M Form
+forAllOr xs avss = do { y <- yes; forAll xs' (y \/ no) }
+  where
+    v         = head (Set.toList xs)
+    xs'       = Set.delete v xs
+    (bs1,bs2) = partition ((v `Set.member`) . snd) avss
+    no        = orl [ b | (b,_) <- bs2 ]
+    body      = orl [ b | (b,_) <- bs1 ]
+    yes       = case bs1 of
+                  []      -> return (orl [])
+                  [(b,_)] -> forAll (Set.singleton v) b
+                  _       -> return (ForAll (Bind (Set.singleton v) body))
+    orl       = foldr (\/) false
+
+----------------------------------------------------------------------
+-- removing equivalences
+
+-- removeEquiv p -> ps :
+--   POST: And ps is equivalent to p (modulo extra symbols)
+--   POST: ps has no Equiv and no Not
+removeEquiv :: Form -> M [Form]
+removeEquiv p =
+  do (defs,pos,_) <- removeEquivAux False p
+     return (pos:defs)
+
+-- removeEquivAux inEquiv p -> (defs,pos,neg) :
+--   PRE: inEquiv is True when we are "under" an Equiv
+--   POST: defs is a list of definitions, under which
+--         pos is equivalent to p and neg is equivalent to nt p
+-- (the reason why "neg" and "nt pos" can be different, is
+-- because we want to always code an equivalence as
+-- a conjunction of two disjunctions, which leads to fewer
+-- clauses -- the "neg" part of the result for the case Equiv
+-- below makes use of this)
+removeEquivAux :: Bool -> Form -> M ([Form],Form,Form)
+removeEquivAux inEquiv p =
+  case simple p of
+    Not p ->
+      do (defs,pos,neg) <- removeEquivAux inEquiv p
+         return (defs,neg,pos)
+  
+    And ps ->
+      do dps <- sequence [ removeEquivAux inEquiv p | p <- ps ]
+         let (defss,poss,negs) = unzip3 dps
+         return ( concat defss
+                , And poss
+                , Or  negs
+                )
+
+    ForAll (Bind xs p) ->
+      do (defs,pos,neg) <- removeEquivAux inEquiv p
+         return ( defs
+                , ForAll (Bind xs pos)
+                , Exists (Bind xs neg)
+                )
+
+    p `Equiv` q ->
+      do (defsp,posp,negp)    <- removeEquivAux True p
+         (defsq,posq,negq)    <- removeEquivAux True q
+         (defsp',posp',negp') <- makeCopyable inEquiv posp negp
+         (defsq',posq',negq') <- makeCopyable inEquiv posq negq
+         return ( concat [defsp, defsq, defsp', defsq']
+                , (negp' \/ posq') /\ (posp' \/ negq')
+                , (negp' \/ negq') /\ (posp' \/ posq')
+                )
+
+    Literal l ->
+      do return ([],Literal l,Literal (neg l))
+
+-- makeCopyable turns an argument to an Equiv into something that we are
+-- willing to copy. There are two such cases: (1) when the Equiv is
+-- not under another Equiv (because we have to copy arguments to an Equiv
+-- at least once anyway), (2) if the formula is small.
+-- All other formulas will be made small (by means of a definition)
+-- before we copy them.
+makeCopyable :: Bool -> Form -> Form -> M ([Form],Form,Form)
+makeCopyable inEquiv pos neg
+  | isSmall pos || not inEquiv =
+    -- we skolemize here so that we reuse the skolem function
+    -- (if we do this after copying, we get several skolemfunctions)
+    do pos' <- removeExists pos
+       neg' <- removeExists neg
+       return ([],pos',neg')
+
+  | otherwise =
+    do dp <- literal "equiv" (free pos)
+       return ([Literal (Neg dp) \/ pos, Literal (Pos dp) \/ neg], Literal (Pos dp), Literal (Neg dp))
+ where
+  -- a formula is small if it is already a literal
+  isSmall (Literal _)         = True
+  isSmall (Not p)             = isSmall p
+  isSmall (ForAll (Bind _ p)) = isSmall p
+  isSmall (Exists (Bind _ p)) = isSmall p
+  isSmall _                   = False
+
+----------------------------------------------------------------------
+-- skolemization
+
+-- removeExists p -> p'
+--   PRE: p has no Equiv and no Not
+--   POST: p' is equivalent to p (modulo extra symbols)
+--   POST: p' has no Equiv, no Exists, and no Not
+removeExists :: Form -> M Form
+removeExists (And ps) =
+  do ps <- sequence [ removeExists p | p <- ps ]
+     return (And ps)
+
+removeExists (Or ps) =
+  do ps <- sequence [ removeExists p | p <- ps ]
+     return (Or ps)
+    
+removeExists (ForAll (Bind xs p)) =
+  do p' <- removeExists p
+     return (ForAll (Bind xs p'))
+    
+removeExists t@(Exists (Bind xs p)) =
+  -- skolemterms have only variables as arguments, arities are large(r)
+  do ss <- sequence [ fmap (x |=>) (skolem x (free t)) | x <- Set.toList xs ]
+     removeExists (subst (foldr (|+|) ids ss) p)
+  {-
+  -- skolemterms can have other skolemterms as arguments, arities are small(er)
+  -- disadvantage: skolemterms are very complicated and deep
+  do p' <- skolemize p
+     t <- skolem x (delete x (free p'))
+     return (subst (x |=> t) p')
+  -}
+
+removeExists lit =
+  do return lit
+
+-- TODO: Avoid recomputing "free" at every step, by having
+-- skolemize return the set of free variables as well
+
+-- TODO: Investigate skolemizing top-down instead, find the right
+-- optimization
+
+----------------------------------------------------------------------
+-- make cheap Ors
+
+removeExpensiveOr :: Form -> M [Form]
+removeExpensiveOr p =
+  do (defs,p',_) <- removeExpensiveOrAux p
+     return (p':defs)
+
+-- cost: represents how it expensive it is to clausify a formula
+type Cost = (Integer,Integer) -- (#clauses, #literals)
+
+unitCost :: Cost
+unitCost = (1,1)
+
+andCost :: [Cost] -> Cost
+andCost cs = (sum (map fst cs), sum (map snd cs))
+
+orCost :: [Cost] -> Cost
+orCost []           = (1,0)
+orCost [c]          = c
+orCost ((c1,l1):cs) = (c1 * c2, c1 * l2 + c2 * l1)
+ where
+  (c2,l2) = orCost cs
+  
+removeExpensiveOrAux :: Form -> M ([Form],Form,Cost)
+removeExpensiveOrAux (And ps) =
+  do dcs <- sequence [ removeExpensiveOrAux p | p <- ps ]
+     let (defss,ps,costs) = unzip3 dcs
+     return (concat defss, And ps, andCost costs)
+
+removeExpensiveOrAux (Or ps) =
+  do dcs <- sequence [ removeExpensiveOrAux p | p <- ps ]
+     let (defss,ps,costs) = unzip3 dcs
+     (defs2,p,c) <- makeOr (sortBy (comparing snd) (zip ps costs))
+     return (defs2 ++ concat defss,p,c)
+
+removeExpensiveOrAux (ForAll (Bind xs p)) =
+  do (defs,p',cost) <- removeExpensiveOrAux p
+     return (fmap (ForAll . Bind xs) defs, ForAll (Bind xs p'), cost)
+
+removeExpensiveOrAux lit =
+  do return ([], lit, unitCost)
+
+-- input is sorted; small costs first
+makeOr :: [(Form,Cost)] -> M ([Form],Form,Cost)
+makeOr [] =
+  do return ([], false, orCost [])
+
+makeOr [(f,c)] =
+  do return ([],f,c)
+
+makeOr fcs
+  | null fcs2 =
+    do return ([], Or (map fst fcs1), orCost (map snd fcs1))
+
+  | otherwise =
+    do d <- literal "or" (free (map fst fcs2))
+       (defs,p,_) <- makeOr ((Literal (Neg d),unitCost):fcs2)
+       return ( p:defs
+              , Or (Literal (Pos d) : map fst fcs1)
+              , orCost (unitCost : map snd fcs1)
+              )
+ where
+  (fcs1,fcs2) = split [] fcs
+  
+  split fcs1 []                            = (fcs1,[])
+  split fcs1 (fc@(_,(cc,_)):fcs) | cc <= 1 = split (fc:fcs1) fcs
+  split fcs1 fcs@((_,(cc,_)):_)  | cc <= 2 = (take 2 fcs ++ fcs1, drop 2 fcs)
+  split fcs1 fcs                           = (take 1 fcs ++ fcs1, drop 1 fcs)
+
+----------------------------------------------------------------------
+-- clausification
+
+-- cnf p = cs
+--   PRE: p has no Equiv, no Exists, and no Not,
+--        and each variable is only bound once
+--   POST: And (map Or cs) is equivalent to p
+cnf :: Form -> [[Literal]]
+cnf (ForAll (Bind _ p)) = cnf p
+cnf (And ps)            = concatMap cnf ps
+cnf (Or ps)             = cross (fmap cnf ps)
+cnf (Literal x)         = [[x]]
+
+cross :: [[[Literal]]] -> [[Literal]]
+cross [] = [[]]
+cross (cs:css) = liftM2 (++) cs (cross css)
+
+----------------------------------------------------------------------
+-- simplification of CNF
+
+simplifyCNF :: [[Literal]] -> [[Literal]]
+simplifyCNF =
+  -- usort: don't generate multiple copies of identical clauses
+  usort . concatMap (tautElim . unify [])
+  where -- remove negative variable equalities X != Y by substitution
+        unify xs [] = xs
+        unify xs (Neg (Var v :=: t@Var{}):ys) =
+          unify (subst (v |=> t) xs) (subst (v |=> t) ys)
+        unify xs (l:ys) = unify (l:xs) ys
+        -- simplify p | ~p or t = t to true.
+        tautElim ls
+          | Set.null (pos `Set.intersection` neg) && not (any tauto ls)
+            -- reorder the order of the literals in the clause
+            -- so that more clauses become equal;
+            -- also, remove duplicate literals from the clause
+            = [map Neg (Set.toList neg) ++ map Pos (Set.toList pos)]
+          | otherwise = []
+          where pos = Set.fromList [ l | Pos l <- ls ]
+                neg = Set.fromList [ l | Neg l <- ls ]
+                tauto (Pos (t :=: u)) = t == u
+                tauto _ = False
+
+----------------------------------------------------------------------
+-- monad
+
+type M = ReaderT Tag NameM
+
+run :: M a -> NameM a
+run x = runReaderT x ""
+
+skolemName :: Named a => String -> a -> M Name
+skolemName prefix v = do
+  s <- getName
+  name <- lift (newName v)
+  return $ withRenamer name $ \str i ->
+    Renaming [prefix ++ show (i+1)] $
+      prefix ++ show (i+1) ++ concat [ "_" ++ t | t <- [s, str], not (null t) ]
+
+withName :: Tag -> M a -> M a
+withName s m = lift (runReaderT m s)
+
+getName :: M Tag
+getName = ask
+
+skolem :: Variable -> Set Variable -> M Term
+skolem (v ::: t) vs =
+  do n <- skolemName "sK" v
+     let f = n ::: FunType (map typ args) t
+     return (f :@: map Var args)
+ where
+  args = Set.toList vs
+
+literal :: String -> Set Variable -> M Atomic
+literal w vs =
+  do n <- skolemName "sP" w
+     let p = n ::: FunType (map typ args) O
+     return (Tru (p :@: map Var args))
+ where
+  args = Set.toList vs
+
+----------------------------------------------------------------------
+-- the end.
diff --git a/src/Jukebox/Form.hs b/src/Jukebox/Form.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/Form.hs
@@ -0,0 +1,669 @@
+-- Formulae, inputs, terms and so on.
+--
+-- "Show" instances for several of these types are found in TPTP.Print.
+
+{-# LANGUAGE DeriveDataTypeable, FlexibleContexts, Rank2Types, GADTs, TypeOperators, ScopedTypeVariables, BangPatterns, PatternGuards #-}
+module Jukebox.Form where
+
+import Prelude hiding (sequence, mapM)
+import qualified Data.Set as Set
+import Data.Set(Set)
+import qualified Data.Map.Strict as Map
+import Data.Map(Map)
+import Data.Ord
+import Jukebox.Name
+import Control.Monad
+import Control.Monad.Trans.Class
+import Control.Monad.Trans.State.Strict
+import Data.List
+import Jukebox.Utils
+import Data.Typeable(Typeable)
+import Data.Monoid
+import qualified Data.DList as DList
+import Data.DList(DList)
+import Data.MemoUgly
+
+-- Set to True to switch on some sanity checks
+debugging :: Bool
+debugging = False
+
+----------------------------------------------------------------------
+-- Types
+
+data DomainSize = Finite Int | Infinite deriving (Eq, Ord, Show, Typeable)
+
+data Type =
+    O
+  | Type {
+      tname :: !Name,
+      -- type is monotone when domain size is >= tmonotone
+      tmonotone :: DomainSize,
+      -- if there is a model of size >= tsize then there is a model of size tsize
+      tsize :: DomainSize } deriving Typeable
+
+data FunType = FunType { args :: [Type], res :: Type } deriving (Eq, Typeable)
+
+-- Helper function for defining (Eq, Ord) instances
+typeMaybeName :: Type -> Maybe Name
+typeMaybeName O = Nothing
+typeMaybeName Type{tname = t} = Just t
+
+instance Eq Type where
+  t1 == t2 = typeMaybeName t1 == typeMaybeName t2
+
+instance Ord Type where
+  compare = comparing typeMaybeName
+
+instance Named Type where
+  name O = name "$o"
+  name Type{tname = t} = t
+
+-- Typeclass of "things that have a type"
+class Typed a where
+  typ :: a -> Type
+
+instance Typed Type where
+  typ = id
+
+instance Typed FunType where
+  typ = res
+
+instance Typed b => Typed (a ::: b) where
+  typ (_ ::: t) = typ t
+
+----------------------------------------------------------------------
+-- Terms
+
+type Variable = Name ::: Type
+type Function = Name ::: FunType
+data Term = Var Variable | Function :@: [Term] deriving (Eq, Ord)
+
+instance Named Term where
+  name (Var x) = name x
+  name (f :@: _) = name f
+
+instance Typed Term where
+  typ (Var x) = typ x
+  typ (f :@: _) = typ f
+
+newSymbol :: Named a => a -> b -> NameM (Name ::: b)
+newSymbol x ty = fmap (::: ty) (newName x)
+
+newFunction :: Named a => a -> [Type] -> Type -> NameM Function
+newFunction x args res = newSymbol x (FunType args res)
+
+newType :: Named a => a -> NameM Type
+newType x = do
+  n <- newName x
+  return (Type n Infinite Infinite)
+
+funArgs :: Function -> [Type]
+funArgs (_ ::: ty) = args ty
+
+arity :: Function -> Int
+arity = length . funArgs
+
+size :: Term -> Int
+size Var{} = 1
+size (_f :@: xs) = 1 + sum (map size xs)
+
+----------------------------------------------------------------------
+-- Literals
+
+infix 8 :=:
+data Atomic = Term :=: Term | Tru Term
+
+-- Helper for (Eq Atomic, Ord Atomic) instances
+normAtomic :: Atomic -> Either (Term, Term) Term
+normAtomic (t1 :=: t2) | t1 > t2 = Left (t2, t1)
+                       | otherwise = Left (t1, t2)
+normAtomic (Tru p) = Right p
+
+instance Eq Atomic where
+  t1 == t2 = normAtomic t1 == normAtomic t2
+
+instance Ord Atomic where
+  compare = comparing normAtomic
+
+data Signed a = Pos a | Neg a deriving (Show, Eq, Ord)
+
+instance Functor Signed where
+  fmap f (Pos x) = Pos (f x)
+  fmap f (Neg x) = Neg (f x)
+type Literal = Signed Atomic
+
+neg :: Signed a -> Signed a
+neg (Pos x) = Neg x
+neg (Neg x) = Pos x
+
+the :: Signed a -> a
+the (Pos x) = x
+the (Neg x) = x
+
+pos :: Signed a -> Bool
+pos (Pos _) = True
+pos (Neg _) = False
+
+signForm :: Signed a -> Form -> Form
+signForm (Pos _) f = f
+signForm (Neg _) f = Not f
+
+----------------------------------------------------------------------
+-- Formulae
+
+-- Invariant: each name is bound only once on each path
+-- i.e. nested quantification of the same variable twice is not allowed
+-- Not OK: ![X]: (... ![X]: ...)
+-- OK:     (![X]: ...) & (![X]: ...)
+-- Free variables must also not be bound inside subformulae
+data Form
+  = Literal Literal
+  | Not Form
+  | And [Form]
+  | Or [Form]
+  | Equiv Form Form
+  | ForAll {-# UNPACK #-} !(Bind Form)
+  | Exists {-# UNPACK #-} !(Bind Form)
+    -- Just exists so that parsing followed by pretty-printing is
+    -- somewhat lossless; the simplify function will get rid of it
+  | Connective Connective Form Form
+
+-- Miscellaneous connectives that exist in TPTP
+data Connective = Implies | Follows | Xor | Nor | Nand
+
+connective :: Connective -> Form -> Form -> Form
+connective Implies t u = nt t \/ u
+connective Follows t u = t \/ nt u
+connective Xor t u = nt (t `Equiv` u)
+connective Nor t u = nt (t \/ u)
+connective Nand t u = nt (t /\ u)
+
+data Bind a = Bind (Set Variable) a
+
+true, false :: Form
+true = And []
+false = Or []
+
+isTrue, isFalse :: Form -> Bool
+isTrue (And []) = True
+isTrue _ = False
+isFalse (Or []) = True
+isFalse _ = False
+
+nt :: Form -> Form
+nt (Not a) = a
+nt a       = Not a
+
+(.=>.) :: Form -> Form -> Form
+(.=>.) = connective Implies
+
+(.=.) :: Term -> Term -> Form
+t .=. u | typ t == O = Literal (Pos (Tru t)) `Equiv` Literal (Pos (Tru u))
+        | otherwise = Literal (Pos (t :=: u))
+
+(/\), (\/) :: Form -> Form -> Form
+And as /\ And bs = And (as ++ bs)
+a      /\ b | isFalse a || isFalse b = false
+And as /\ b      = And (b:as)
+a      /\ And bs = And (a:bs)
+a      /\ b      = And [a, b]
+
+Or as \/ Or bs = Or (as ++ bs)
+a     \/ b | isTrue a || isTrue b = true
+Or as \/ b     = Or (b:as)
+a     \/ Or bs = Or (a:bs)
+a     \/ b     = Or [a, b]
+
+closeForm :: Form -> Form
+closeForm f | Set.null vars = f
+            | otherwise = ForAll (Bind vars f)
+  where vars = free f
+
+-- remove Not from the root of a problem
+positive :: Form -> Form
+positive (Not f) = notInwards f
+-- Some connectives are fairly not-ish
+positive (Connective c t u)         = positive (connective c t u)
+positive f = f
+
+notInwards :: Form -> Form
+notInwards (And as)             = Or (fmap notInwards as)
+notInwards (Or as)              = And (fmap notInwards as)
+notInwards (a `Equiv` b)        = notInwards a `Equiv` b
+notInwards (Not a)              = positive a
+notInwards (ForAll (Bind vs a)) = Exists (Bind vs (notInwards a))
+notInwards (Exists (Bind vs a)) = ForAll (Bind vs (notInwards a))
+notInwards (Literal l)          = Literal (neg l)
+notInwards (Connective c t u)   = notInwards (connective c t u)
+
+-- remove Exists and Or from the top level of a formula
+simple :: Form -> Form
+simple (Or as)              = Not (And (fmap nt as))
+simple (Exists (Bind vs a)) = Not (ForAll (Bind vs (nt a)))
+simple (Connective c t u)   = simple (connective c t u)
+simple a                    = a
+
+-- perform some easy algebraic simplifications
+simplify t@Literal{} = t
+simplify (Connective c t u) = simplify (connective c t u)
+simplify (Not t) = simplify (notInwards t)
+simplify (And ts) = foldr (/\) true (fmap simplify ts)
+simplify (Or ts) = foldr (\/) false (fmap simplify ts)
+simplify (Equiv t u) = equiv (simplify t) (simplify u)
+  where equiv t u | isTrue t = u
+                  | isTrue u = t
+                  | isFalse t = nt u
+                  | isFalse u = nt t
+                  | otherwise = Equiv t u
+simplify (ForAll (Bind vs t)) = forAll vs (simplify t)
+  where forAll vs t | Set.null vs = t
+        forAll vs (ForAll (Bind vs' t)) = ForAll (Bind (Set.union vs vs') t)
+        forAll vs t = ForAll (Bind vs t)
+simplify (Exists (Bind vs t)) = exists vs (simplify t)
+  where exists vs t | Set.null vs = t
+        exists vs (Exists (Bind vs' t)) = Exists (Bind (Set.union vs vs') t)
+        exists vs t = Exists (Bind vs t)
+
+----------------------------------------------------------------------
+-- Clauses
+
+data CNF =
+  CNF {
+    axioms :: [Input Clause],
+    conjectures :: [[Input Clause]],
+    satisfiable :: String,
+    unsatisfiable :: String }
+
+toCNF :: [Input Clause] -> [[Input Clause]] -> CNF
+toCNF axioms [] = CNF axioms [[]] "Satisfiable" "Unsatisfiable"
+toCNF axioms [conjecture] = CNF axioms [conjecture] "CounterSatisfiable" "Theorem"
+toCNF axioms conjectures = CNF axioms conjectures "GaveUp" "Theorem"
+
+newtype Clause = Clause (Bind [Literal])
+
+clause :: [Signed Atomic] -> Clause
+clause xs = Clause (bind xs)
+
+toForm :: Clause -> Form
+toForm (Clause (Bind vs ls)) = ForAll (Bind vs (Or (map Literal ls)))
+
+toLiterals :: Clause -> [Literal]
+toLiterals (Clause (Bind _ ls)) = ls
+
+----------------------------------------------------------------------
+-- Problems
+
+type Tag = String
+
+data Kind = Axiom | Conjecture | Question deriving (Eq, Ord)
+
+data Answer = Satisfiable | Unsatisfiable | NoAnswer NoAnswerReason
+  deriving (Eq, Ord)
+
+instance Show Answer where
+  show Satisfiable = "Satisfiable"
+  show Unsatisfiable = "Unsatisfiable"
+  show (NoAnswer x) = show x
+
+data NoAnswerReason = GaveUp | Timeout deriving (Eq, Ord, Show)
+
+data Input a = Input
+  { tag ::  Tag,
+    kind :: Kind,
+    what :: a }
+
+type Problem a = [Input a]
+
+instance Functor Input where
+  fmap f x = x { what = f (what x) }
+
+----------------------------------------------------------------------
+-- Symbolic stuff
+
+-- A universe of types with typecase
+data TypeOf a where
+  Form :: TypeOf Form
+  Clause_ :: TypeOf Clause
+  Term :: TypeOf Term
+  Atomic :: TypeOf Atomic
+  Signed :: (Symbolic a, Symbolic (Signed a)) => TypeOf (Signed a)
+  Bind_ :: (Symbolic a, Symbolic (Bind a)) => TypeOf (Bind a)
+  List :: (Symbolic a, Symbolic [a]) => TypeOf [a]
+  Input_ :: (Symbolic a, Symbolic (Input a)) => TypeOf (Input a)
+  CNF_ :: TypeOf CNF
+
+class Symbolic a where
+  typeOf :: a -> TypeOf a
+
+instance Symbolic Form where typeOf _ = Form
+instance Symbolic Clause where typeOf _ = Clause_
+instance Symbolic Term where typeOf _ = Term
+instance Symbolic Atomic where typeOf _ = Atomic
+instance Symbolic a => Symbolic (Signed a) where typeOf _ = Signed
+instance Symbolic a => Symbolic (Bind a) where typeOf _ = Bind_
+instance Symbolic a => Symbolic [a] where typeOf _ = List
+instance Symbolic a => Symbolic (Input a) where typeOf _ = Input_
+instance Symbolic CNF where typeOf _ = CNF_
+
+-- Generic representations of values.
+data Rep a where
+  Const :: !a -> Rep a
+  Unary :: Symbolic a => (a -> b) -> a -> Rep b
+  Binary :: (Symbolic a, Symbolic b) => (a -> b -> c) -> a -> b -> Rep c
+
+-- This inline declaration is crucial so that
+-- pattern-matching on a rep degenerates into typecase.
+{-# INLINE rep #-}
+rep :: Symbolic a => a -> Rep a
+rep x =
+  case typeOf x of
+    Form -> rep' x
+    Clause_ -> rep' x
+    Term -> rep' x
+    Atomic -> rep' x
+    Signed -> rep' x
+    Bind_ -> rep' x
+    List -> rep' x
+    Input_ -> rep' x
+    CNF_ -> rep' x
+
+-- Implementation of rep for all types
+class Unpack a where
+  rep' :: a -> Rep a
+
+instance Unpack Form where
+  rep' (Literal l) = Unary Literal l
+  rep' (Not t) = Unary Not t
+  rep' (And ts) = Unary And ts
+  rep' (Or ts) = Unary Or ts
+  rep' (Equiv t u) = Binary Equiv t u
+  rep' (ForAll b) = Unary ForAll b
+  rep' (Exists b) = Unary Exists b
+  rep' (Connective c t u) = Binary (Connective c) t u
+
+instance Unpack Clause where
+  rep' (Clause ls) = Unary Clause ls
+
+instance Unpack Term where
+  rep' t@Var{} = Const t
+  rep' (f :@: ts) = Unary (f :@:) ts
+
+instance Unpack Atomic where
+  rep' (t :=: u) = Binary (:=:) t u
+  rep' (Tru p) = Unary Tru p
+
+instance Symbolic a => Unpack (Signed a) where
+  rep' (Pos x) = Unary Pos x
+  rep' (Neg x) = Unary Neg x
+
+instance Symbolic a => Unpack (Bind a) where
+  rep' (Bind vs x) = Unary (Bind vs) x
+
+instance Symbolic a => Unpack [a] where
+  rep' [] = Const []
+  rep' (x:xs) = Binary (:) x xs
+
+instance Symbolic a => Unpack (Input a) where
+  rep' (Input tag kind what) = Unary (Input tag kind) what
+
+instance Unpack CNF where
+  rep' (CNF ax conj s1 s2) =
+    Binary (\ax' conj' -> CNF ax' conj' s1 s2) ax conj
+
+-- Little generic strategies
+
+{-# INLINE recursively #-}
+recursively :: Symbolic a => (forall a. Symbolic a => a -> a) -> a -> a
+recursively h t =
+  case rep t of
+    Const x -> x
+    Unary f x -> f (h x)
+    Binary f x y -> f (h x) (h y)
+
+{-# INLINE recursivelyM #-}
+recursivelyM :: (Monad m, Symbolic a) => (forall a. Symbolic a => a -> m a) -> a -> m a
+recursivelyM h t =
+  case rep t of
+    Const x -> return x
+    Unary f x -> liftM f (h x)
+    Binary f x y -> liftM2 f (h x) (h y)
+
+{-# INLINE collect #-}
+collect :: (Symbolic a, Monoid b) => (forall a. Symbolic a => a -> b) -> a -> b
+collect h t =
+  case rep t of
+    Const _x -> mempty
+    Unary _f x -> h x
+    Binary _f x y -> h x `mappend` h y
+
+----------------------------------------------------------------------
+-- Substitutions
+
+type Subst = Map Variable Term
+
+ids :: Subst
+ids = Map.empty
+
+(|=>) :: Variable -> Term -> Subst
+v |=> x = Map.singleton v x
+
+(|+|) :: Subst -> Subst -> Subst
+(|+|) = Map.union
+
+subst :: Symbolic a => Subst -> a -> a
+subst s t =
+  case typeOf t of
+    Term -> term t
+    Bind_ -> bind t
+    _ -> generic t
+  where
+    term (Var x)
+      | Just u <- Map.lookup x s = u
+    term t = generic t
+
+    bind :: Symbolic a => Bind a -> Bind a
+    bind (Bind vs t) =
+      Bind vs (subst (checkBinder vs (Map.filterWithKey (\x _ -> x `Set.member` vs) s)) t)
+
+    generic :: Symbolic a => a -> a
+    generic t = recursively (subst s) t
+
+----------------------------------------------------------------------
+-- Functions operating on symbolic terms
+
+free :: Symbolic a => a -> Set Variable
+free t
+  | Term <- typeOf t,
+    Var x <- t        = var x
+  | Bind_ <- typeOf t = bind t
+  | otherwise         = collect free t
+  where
+    var :: Variable -> Set Variable
+    var x = Set.singleton x
+
+    bind :: Symbolic a => Bind a -> Set Variable
+    bind (Bind vs t) = free t Set.\\ vs
+
+ground :: Symbolic a => a -> Bool
+ground = Set.null . free
+
+bind :: Symbolic a => a -> Bind a
+bind x = Bind (free x) x
+
+-- Helper function for collecting information from terms and binders.
+termsAndBinders :: forall a b.
+                   Symbolic a =>
+                   (Term -> DList b) ->
+                   (forall a. Symbolic a => Bind a -> [b]) ->
+                   a -> [b]
+termsAndBinders term bind = DList.toList . aux where
+  aux :: Symbolic c => c -> DList b
+  aux t =
+    collect aux t `mplus`
+    case typeOf t of
+      Term -> term t
+      Bind_ -> DList.fromList (bind t)
+      _ -> mzero
+
+names :: Symbolic a => a -> [Name]
+names = usort . termsAndBinders term bind where
+  term t = return (name t) `mappend` return (name (typ t))
+
+  bind :: Symbolic a => Bind a -> [Name]
+  bind (Bind vs _) = map name (Set.toList vs)
+
+run :: Symbolic a => a -> (a -> NameM b) -> b
+run x f = runNameM (names x) (f x)
+
+types :: Symbolic a => a -> [Type]
+types = usort . termsAndBinders term bind where
+  term t = return (typ t)
+
+  bind :: Symbolic a => Bind a -> [Type]
+  bind (Bind vs _) = map typ (Set.toList vs)
+
+types' :: Symbolic a => a -> [Type]
+types' = filter (/= O) . types
+
+terms :: Symbolic a => a -> [Term]
+terms = usort . termsAndBinders term mempty where
+  term t = return t
+
+vars :: Symbolic a => a -> [Variable]
+vars = usort . termsAndBinders term bind where
+  term (Var x) = return x
+  term _ = mempty
+
+  bind :: Symbolic a => Bind a -> [Variable]
+  bind (Bind vs _) = Set.toList vs
+
+functions :: Symbolic a => a -> [Function]
+functions = usort . termsAndBinders term mempty where
+  term (f :@: _) = return f
+  term _ = mempty
+
+isFof :: Symbolic a => a -> Bool
+isFof f = length (types' f) <= 1
+
+uniqueNames :: Symbolic a => a -> NameM a
+uniqueNames t = evalStateT (aux Map.empty t) (Map.fromList [(x, t) | x ::: t <- Set.toList (free t)])
+  where aux :: Symbolic a => Subst -> a -> StateT (Map Name Type) NameM a
+        aux s t =
+          case typeOf t of
+            Term -> term s t
+            Bind_ -> bind s t
+            _ -> generic s t
+
+        term :: Subst -> Term -> StateT (Map Name Type) NameM Term
+        term s t@(Var x) = do
+          case Map.lookup x s of
+            Nothing -> return t
+            Just u -> return u
+        term s t = generic s t
+
+        bind :: Symbolic a => Subst -> Bind a -> StateT (Map Name Type) NameM (Bind a)
+        bind s (Bind vs x) = do
+          used <- get
+          let (stale, fresh) = partition ((`Map.member` used) . lhs) (Set.toList vs)
+              tuple (x ::: y) = (x, y)
+          stale' <- sequence [ lift (newSymbol x t) | x ::: t <- stale ]
+          put (used `Map.union` Map.fromList (map tuple (fresh ++ stale')))
+          case stale of
+            [] -> fmap (Bind vs) (aux s x)
+            _ ->
+              do
+                let s' = Map.fromList [(x, Var y) | (x, y) <- stale `zip` stale'] `Map.union` s
+                    vs' = Set.fromList (stale' ++ fresh)
+                fmap (Bind vs') (aux s' x)
+
+        generic :: Symbolic a => Subst -> a -> StateT (Map Name Type) NameM a
+        generic s t = recursivelyM (aux s) t
+
+-- Force a value.
+force :: Symbolic a => a -> a
+force x = rnf x `seq` x
+  where rnf :: Symbolic a => a -> ()
+        rnf x =
+          case rep x of
+            Const !_ -> ()
+            Unary _ x -> rnf x
+            Binary _ x y -> rnf x `seq` rnf y
+
+-- Check that there aren't two nested binders binding the same variable
+check :: Symbolic a => a -> a
+check x | not debugging = x
+        | check' (free x) x = x
+        | otherwise = error "Form.check: invariant broken"
+  where check' :: Symbolic a => Set Variable -> a -> Bool
+        check' vars t =
+          case typeOf t of
+            Term -> term vars t
+            Bind_ -> bind vars t
+            _ -> generic vars t
+
+        term :: Set Variable -> Term -> Bool
+        term vars (Var x) = x `Set.member` vars
+        term vars t = generic vars t
+
+        bind :: Symbolic a => Set Variable -> Bind a -> Bool
+        bind vars (Bind vs t) =
+          Set.null (vs `Set.intersection` vars) &&
+          check' (vs `Set.union` vars) t
+
+        generic :: Symbolic a => Set Variable -> a -> Bool
+        generic vars = getAll . collect (All . check' vars)
+
+-- Check that a binder doesn't capture variables from a substitution.
+checkBinder :: Set Variable -> Subst -> Subst
+checkBinder vs s | not debugging = s
+                 | Set.null (free (Map.elems s) `Set.intersection` vs) = s
+                 | otherwise = error "Form.checkBinder: capturing substitution"
+
+-- Apply a function to each name, while preserving sharing.
+mapName :: Symbolic a => (Name -> Name) -> a -> a
+mapName f0 = rename
+  where
+    rename :: Symbolic a => a -> a
+    rename t =
+      case typeOf t of
+        Term -> term t
+        Bind_ -> bind t
+        _ -> recursively rename t
+
+    bind :: Symbolic a => Bind a -> Bind a
+    bind (Bind vs t) =  Bind (Set.map var vs) (rename t)
+    term (f :@: ts) = fun f :@: map term ts
+    term (Var x) = Var (var x)
+
+    var = memo $ \(x ::: ty) -> f x ::: type_ ty
+    fun = memo $ \(x ::: FunType args res) ->
+                   f x ::: FunType (map type_ args) (type_ res)
+    type_ =
+      memo $ \ty ->
+        case ty of
+          O -> O
+          Type name x y -> Type (f name) x y
+
+    f = memo f0
+
+-- Apply a function to each type, while preserving sharing.
+mapType :: Symbolic a => (Type -> Type) -> a -> a
+mapType f0 = mapType'
+  where mapType' :: Symbolic a => a -> a
+        mapType' t =
+          case typeOf t of
+            Term -> term t
+            Bind_ -> bind t
+            _ -> recursively mapType' t
+
+        bind :: Symbolic a => Bind a -> Bind a
+        bind (Bind vs t) = Bind (Set.map var vs) (mapType' t)
+
+        term (f :@: ts) = fun f :@: map term ts
+        term (Var x) = Var (var x)
+
+        var = memo $ \(x ::: ty) -> x ::: f ty
+        fun = memo $ \(x ::: FunType args res) ->
+                       x ::: FunType (map f args) (f res)
+
+        f = memo f0
diff --git a/src/Jukebox/GuessModel.hs b/src/Jukebox/GuessModel.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/GuessModel.hs
@@ -0,0 +1,121 @@
+{-# LANGUAGE GADTs, PatternGuards #-}
+module Jukebox.GuessModel where
+
+import Control.Monad
+import Jukebox.Name
+import Jukebox.Form
+import Jukebox.TPTP.Print
+import Jukebox.TPTP.ParseSnippet
+import Jukebox.Utils
+
+data Universe = Peano | Trees
+
+universe :: Universe -> Type -> NameM ([Function], [Form])
+universe Peano = peano
+universe Trees = trees
+
+peano i = do
+  zero <- newFunction "zero" [] i
+  succ <- newFunction "succ" [i] i
+  pred <- newFunction "pred" [i] i
+  let types = [("$i", i)]
+      funs = [("zero", zero),
+              ("succ", succ),
+              ("pred", pred)]
+  
+  let prelude =
+        map (cnf types funs) [
+          "zero != succ(X)",
+          "pred(succ(X)) = X"
+        ]
+  return ([zero, succ], prelude)
+
+trees i = do
+  nil <- newFunction "nil" [] i
+  bin <- newFunction "bin" [i, i] i
+  left <- newFunction "left" [i] i
+  right <- newFunction "right" [i] i
+  let types = [("$i", i)]
+      funs = [("nil", nil),
+              ("bin", bin),
+              ("left", left),
+              ("right", right)]
+  
+  let prelude =
+        map (cnf types funs) [
+          "nil != bin(X,Y)",
+          "left(bin(X,Y)) = X",
+          "right(bin(X,Y)) = Y"
+        ]
+  return ([nil, bin], prelude)
+
+guessModel :: [String] -> Universe -> Problem Form -> Problem Form
+guessModel expansive univ prob = run prob $ \forms -> do
+  let i = ind forms
+  answerType <- newType "answer"
+  answer <- newFunction "$answer" [answerType] O
+  let withExpansive f func = f func (base (name func) `elem` expansive) answer
+  (constructors, prelude) <- universe univ i
+  program <- fmap concat (mapM (withExpansive (function constructors)) (functions forms))
+  return (map (Input "adt" Axiom) prelude ++
+          map (Input "program" Axiom) program ++
+          forms)
+
+ind :: Symbolic a => a -> Type
+ind x =
+  case types' x of
+    [ty] -> ty
+    [] -> Type (name "$i") Infinite Infinite
+    _ -> error "GuessModel: can't deal with many-typed problems"
+
+function :: [Function] -> Function -> Bool -> Function -> NameM [Form]
+function constructors f expansive answerP = fmap concat $ do
+  argss <- cases constructors (funArgs f)
+  forM argss $ \args -> do
+    fname <- newFunction ("exhausted_" ++ base (name f) ++ "_case")
+               [] (head (funArgs answerP))
+    let answer = Literal (Pos (Tru (answerP :@: [fname :@: []])))
+    let theRhss = rhss constructors args f expansive answer
+    alts <- forM theRhss $ \rhs -> do
+      pred <- newFunction (concat (lines (prettyShow rhs))) [] O
+      return (Literal (Pos (Tru (pred :@: []))))
+    return $
+      foldr (\/) false alts:
+      [ closeForm (Connective Implies alt rhs)
+      | (alt, rhs) <- zip alts theRhss ]
+
+rhss :: [Function] -> [Term] -> Function -> Bool -> Form -> [Form]
+rhss constructors args f expansive answer =
+  case typ f of
+    O ->
+      Literal (Pos (Tru (f :@: args))):
+      Literal (Neg (Tru (f :@: args))):
+      map its (map (f :@:) (recursive args))
+    _ | expansive -> map its (usort (unconditional ++ constructor))
+      | otherwise -> map its (usort unconditional) ++ [answer]
+  where recursive [] = []
+        recursive (a:as) = reduce a ++ map (a:) (recursive as)
+          where reduce (_f :@: xs) = [ x:as' | x <- xs, as' <- as:recursive as ]
+                reduce _ = []
+        constructor = [ c :@: xs
+                      | c <- constructors,
+                        xs <- sequence (replicate (arity c) unconditional) ]
+        
+        subterm = terms args
+        its t = f :@: args .=. t
+        unconditional = map (f :@:) (recursive args) ++ subterm
+
+cases :: [Function] -> [Type] -> NameM [[Term]]
+cases _constructors [] = return [[]]
+cases constructors (ty:tys) = do
+  ts <- cases1 constructors ty
+  tss <- cases constructors tys
+  return (liftM2 (:) ts tss)
+
+cases1 :: [Function] -> Type -> NameM [Term]
+cases1 constructors ty = do
+  let maxArity = maximum (map arity constructors)
+      varNames = take maxArity (cycle ["X", "Y", "Z"])
+  vars <- mapM (flip newSymbol ty) varNames
+  return [ c :@: take (arity c) (map Var vars)
+         | c <- constructors ]
diff --git a/src/Jukebox/HighSat.hs b/src/Jukebox/HighSat.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/HighSat.hs
@@ -0,0 +1,106 @@
+{-# LANGUAGE BangPatterns, GeneralizedNewtypeDeriving #-}
+module Jukebox.HighSat where
+
+import MiniSat hiding (neg)
+import qualified MiniSat
+import Jukebox.Form(Signed(..), neg)
+import qualified Data.Map.Strict as Map
+import Data.Map(Map)
+import Control.Monad
+import Control.Monad.Trans.Class
+import Control.Monad.IO.Class
+import Control.Monad.Trans.State.Strict
+import Control.Monad.Trans.Reader
+import Data.Maybe
+
+newtype Sat1 a b = Sat1 { runSat1_ :: ReaderT Solver (ReaderT (Watch a) (StateT (Map a Lit) IO)) b } deriving (Functor, Applicative, Monad, MonadIO)
+newtype Sat a b c = Sat { runSat_ :: ReaderT (Watch a) (StateT (Map b (SatState a)) IO) c } deriving (Functor, Applicative, Monad, MonadIO)
+data SatState a = SatState Solver (Map a Lit)
+type Watch a = a -> Sat1 a ()
+
+data Form a
+  = Lit (Signed a)
+  | And [Form a]
+  | Or [Form a]
+
+nt :: Form a -> Form a
+nt (Lit x) = Lit (neg x)
+nt (And xs) = Or (fmap nt xs)
+nt (Or xs) = And (fmap nt xs)
+
+true, false :: Form a
+true = And []
+false = Or []
+
+unique :: [Form a] -> Form a
+unique = u
+  where u [] = true
+        u [_] = true
+        u (x:xs) = And [Or [nt x, And (map nt xs)],
+                        u xs]
+
+runSat :: Ord b => Watch a -> [b] -> Sat a b c -> IO c
+runSat w idxs x = go idxs Map.empty
+  where go [] m = evalStateT (runReaderT (runSat_ x) w) m
+        go (idx:idxs) m =
+          withNewSolver $ \s -> go idxs (Map.insert idx (SatState s Map.empty) m)
+
+runSat1 :: Ord a => Watch a -> Sat1 a b -> IO b
+runSat1 w x = runSat w [()] (atIndex () x)
+
+atIndex :: (Ord a, Ord b) => b -> Sat1 a c -> Sat a b c
+atIndex !idx m = do
+  watch <- Sat ask
+  SatState s ls <- Sat (lift (gets (Map.findWithDefault (error "withSolver: index not found") idx)))
+  (x, ls') <- liftIO (runStateT (runReaderT (runReaderT (runSat1_ m) s) watch) ls)
+  Sat (lift (modify (Map.insert idx (SatState s ls'))))
+  return x
+
+solve :: Ord a => [Signed a] -> Sat1 a Bool
+solve xs = do
+  s <- Sat1 ask
+  ls <- mapM lit xs
+  liftIO (MiniSat.solve s ls)
+
+model :: Ord a => Sat1 a (a -> Bool)
+model = do
+  s <- Sat1 ask
+  m <- Sat1 (lift (lift get))
+  vals <- liftIO (traverse (MiniSat.modelValue s) m)
+  return (\v -> fromMaybe False (Map.findWithDefault Nothing v vals))
+
+modelValue :: Ord a => a -> Sat1 a Bool
+modelValue x = do
+  s <- Sat1 ask
+  l <- var x
+  Just b <- liftIO (MiniSat.modelValue s l)
+  return b
+
+addForm :: Ord a => Form a -> Sat1 a ()
+addForm f = do
+  s <- Sat1 ask
+  cs <- flatten f
+  liftIO (mapM (MiniSat.addClause s) cs)
+  return ()
+
+flatten :: Ord a => Form a -> Sat1 a [[Lit]]
+flatten (Lit l) = fmap (return . return) (lit l)
+flatten (And fs) = fmap concat (mapM flatten fs)
+flatten (Or fs) = fmap (fmap concat . sequence) (mapM flatten fs)
+
+lit :: Ord a => Signed a -> Sat1 a Lit
+lit (Pos x) = var x
+lit (Neg x) = liftM MiniSat.neg (var x)
+
+var :: Ord a => a -> Sat1 a Lit
+var x = do
+  s <- Sat1 ask
+  m <- Sat1 (lift (lift get))
+  case Map.lookup x m of
+    Nothing -> do
+      l <- liftIO (MiniSat.newLit s)
+      Sat1 (lift (lift (put (Map.insert x l m))))
+      w <- Sat1 (lift ask)
+      w x
+      return l
+    Just l -> return l
diff --git a/src/Jukebox/InferTypes.hs b/src/Jukebox/InferTypes.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/InferTypes.hs
@@ -0,0 +1,86 @@
+{-# LANGUAGE TypeOperators, GADTs, CPP #-}
+module Jukebox.InferTypes where
+
+#include "errors.h"
+import Control.Monad
+import Jukebox.Form
+import Jukebox.Name
+import qualified Data.Map.Strict as Map
+import Data.Map(Map)
+import Jukebox.UnionFind hiding (rep)
+import qualified Data.Set as Set
+import Data.MemoUgly
+
+type Function' = ([(Name, Type)], (Name, Type))
+
+inferTypes :: [Input Clause] -> NameM ([Input Clause], Type -> Type)
+inferTypes prob = do
+  funMap <-
+    fmap Map.fromList . sequence $
+      [ do res <- newName (typ f)
+           args <- mapM newName (funArgs f)
+           return (name f,
+                   (zipWith (,) args (funArgs f),
+                    (res, typ f)))
+      | f <- functions prob ]
+  varMap <-
+    fmap Map.fromList . sequence $
+      [ do ty <- newName (typ v)
+           return (name v, (ty, typ v))
+      | v <- vars prob ]
+  
+  let tyMap = Map.fromList $
+              concat [ res:args | (args, res) <- Map.elems funMap ] ++
+              [ ty | ty <- Map.elems varMap ]
+  
+  let (prob', rep) = solve funMap varMap prob
+      rep' ty =
+        Map.findWithDefault __ (rep (name ty)) tyMap
+  
+  return (prob', rep')
+
+solve :: Map Name Function' -> Map Name (Name, Type) ->
+         [Input Clause] -> ([Input Clause], Name -> Name)
+solve funMap varMap prob = (prob', rep)
+  where prob' = aux prob
+        aux :: Symbolic a => a -> a
+        aux t =
+          case typeOf t of
+            Bind_ -> bind t
+            Term -> term t
+            _ -> recursively aux t
+
+        bind :: Symbolic a => Bind a -> Bind a
+        bind (Bind vs t) = Bind (Set.map var vs) (aux t)
+
+        term (f :@: ts) = fun f :@: map term ts
+        term (Var x) = Var (var x)
+
+        fun = memo fun_
+        fun_ (f ::: _) =
+          let (args, res) = Map.findWithDefault __ f funMap
+          in f ::: FunType (map type_ args) (type_ res)
+
+        var = memo var_
+        var_ (x ::: _) = x ::: type_ (Map.findWithDefault __ x varMap)
+
+        type_ = memo type__
+        type__ (_, O) = O
+        type__ (name, _) = Type (rep name) Infinite Infinite
+
+        rep = evalUF initial $ do
+          generate funMap varMap prob
+          reps
+
+generate :: Map Name Function' -> Map Name (Name, Type) -> [Input Clause] -> UF Name ()
+generate funMap varMap cs = mapM_ (mapM_ atomic) lss
+  where lss = map (map the . toLiterals . what) cs
+        atomic (Tru p) = void (term p)
+        atomic (t :=: u) = do { t' <- term t; u' <- term u; t' =:= u'; return () }
+        term (Var x) = return y
+          where (y, _) = Map.findWithDefault __ (name x) varMap
+        term (f :@: xs) = do
+          ys <- mapM term xs
+          let (zs, r) = Map.findWithDefault __ (name f) funMap
+          zipWithM_ (=:=) ys (map fst zs)
+          return (fst r)
diff --git a/src/Jukebox/Monotonox/Monotonicity.hs b/src/Jukebox/Monotonox/Monotonicity.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/Monotonox/Monotonicity.hs
@@ -0,0 +1,76 @@
+{-# LANGUAGE TypeOperators #-}
+module Jukebox.Monotonox.Monotonicity where
+
+import Prelude hiding (lookup)
+import Jukebox.Name
+import Jukebox.Form hiding (Form, clause, true, false, And, Or)
+import Jukebox.HighSat
+import Control.Monad
+import qualified Data.Map.Strict as Map
+import Data.Map(Map)
+
+data Extension = TrueExtend | FalseExtend | CopyExtend deriving Show
+
+data Var = FalseExtended Function | TrueExtended Function deriving (Eq, Ord)
+
+annotateMonotonicity :: Problem Clause -> IO (Problem Clause)
+annotateMonotonicity prob = do
+  m <- monotone (map what prob)
+  let f O = O
+      f ty =
+        case Map.lookup ty m of
+          Nothing -> ty
+          Just{} -> ty { tmonotone = Finite 0 }
+  return (fmap (mapType f) prob)
+
+monotone :: [Clause] -> IO (Map Type (Maybe (Map Function Extension)))
+monotone cs = runSat watch tys $ do
+  let fs = functions cs
+  mapM_ (clause . toLiterals) cs
+  fmap Map.fromList . forM tys $ \ty -> atIndex ty $ do
+    r <- solve []
+    case r of
+      False -> return (ty, Nothing)
+      True -> do
+        m <- model
+        return (ty, Just (fromModel fs ty m))
+  where watch (FalseExtended f) =
+          addForm (Or [Lit (Neg (FalseExtended f)),
+                       Lit (Neg (TrueExtended f))])
+        watch _ = return ()
+        tys = types' cs
+
+fromModel :: [Function] -> Type -> (Var -> Bool) -> Map Function Extension
+fromModel fs ty m = Map.fromList [ (f, extension f m) | f <- fs, typ f == O, ty `elem` args (rhs f) ]
+
+extension :: Function -> (Var -> Bool) -> Extension
+extension f m =
+  case (m (FalseExtended f), m (TrueExtended f)) of
+    (False, False) -> CopyExtend
+    (True, False) -> FalseExtend
+    (False, True) -> TrueExtend
+
+clause :: [Literal] -> Sat Var Type ()
+clause ls = mapM_ (literal ls) ls
+
+literal :: [Literal] -> Literal -> Sat Var Type ()
+literal ls (Pos (t :=: u)) = atIndex (typ t) $ do
+  addForm (safe ls t)
+  addForm (safe ls u)
+literal _ls (Neg (_ :=: _)) = return ()
+literal ls (Pos (Tru (p :@: ts))) =
+  forM_ ts $ \t -> atIndex (typ t) $ addForm (Or [safe ls t, Lit (Neg (FalseExtended p))])
+literal ls (Neg (Tru (p :@: ts))) =
+  forM_ ts $ \t -> atIndex (typ t) $ addForm (Or [safe ls t, Lit (Neg (TrueExtended p))])
+
+safe :: [Literal] -> Term -> Form Var
+safe ls (Var x) = Or [ guards l x | l <- ls ]
+safe _ _ = true
+
+guards :: Literal -> Variable -> Form Var
+guards (Neg (Var _ :=: Var _)) _ = error "Monotonicity.guards: found a variable inequality X!=Y after clausification"
+guards (Neg (Var x :=: _)) y | x == y = true
+guards (Neg (_ :=: Var x)) y | x == y = true
+guards (Pos (Tru (p :@: ts))) x | Var x `elem` ts = Lit (Pos (TrueExtended p))
+guards (Neg (Tru (p :@: ts))) x | Var x `elem` ts = Lit (Pos (FalseExtended p))
+guards _ _ = false
diff --git a/src/Jukebox/Monotonox/ToFOF.hs b/src/Jukebox/Monotonox/ToFOF.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/Monotonox/ToFOF.hs
@@ -0,0 +1,192 @@
+{-# LANGUAGE GADTs, PatternGuards #-}
+module Jukebox.Monotonox.ToFOF where
+
+import Jukebox.Clausify(split, removeEquiv, run, withName)
+import Jukebox.Name
+import Jukebox.Form hiding (run)
+import qualified Jukebox.Form as Form
+import Jukebox.Options
+import Control.Monad hiding (guard)
+import Data.Monoid
+import qualified Data.Map.Strict as Map
+import qualified Data.Set as Set
+
+data Scheme = Scheme {
+  makeFunction :: Type -> NameM Function,
+  scheme1 :: (Type -> Bool) -> (Type -> Function) -> Scheme1
+  }
+
+data Scheme1 = Scheme1 {
+  forAll :: Bind Form -> Form,
+  exists :: Bind Form -> Form,
+  equals :: Term -> Term -> Form,
+  funcAxiom :: Function -> NameM Form,
+  typeAxiom :: Type -> NameM Form
+  }
+
+guard :: Scheme1 -> (Type -> Bool) -> Input Form -> Input Form
+guard scheme mono (Input t k f) = Input t k (aux (pos k) f)
+  where aux pos (ForAll (Bind vs f))
+          | pos = forAll scheme (Bind vs (aux pos f))
+          | otherwise = Not (exists scheme (Bind vs (Not (aux pos f))))
+        aux pos (Exists (Bind vs f))
+          | pos = exists scheme (Bind vs (aux pos f))
+          | otherwise = Not (forAll scheme (Bind vs (Not (aux pos f))))
+        aux _pos (Literal (Pos (t :=: u)))
+          | not (mono (typ t)) = equals scheme t u
+        aux _pos (Literal (Neg (t :=: u)))
+          | not (mono (typ t)) = Not (equals scheme t u)
+        aux _pos l@Literal{} = l
+        aux pos (Not f) = Not (aux (not pos) f)
+        aux pos (And fs) = And (fmap (aux pos) fs)
+        aux pos (Or fs) = Or (fmap (aux pos) fs)
+        aux _pos (Equiv _ _) = error "ToFOF.guard: equiv should have been eliminated"
+        aux _pos (Connective _ _ _) = error "ToFOF.guard: connective should have been eliminated"
+        pos Axiom = True
+        pos Conjecture = False
+
+translate, translate1 :: Scheme -> (Type -> Bool) -> Problem Form -> Problem Form
+translate1 scheme mono f = Form.run f $ \inps -> do
+  let tys = types' inps
+      funcs = functions inps
+      -- Hardly any use adding guards if there's only one type.
+      mono' | length tys == 1 = const True
+            | otherwise = mono
+  typeFuncs <- mapM (makeFunction scheme) tys
+  let typeMap = Map.fromList (zip tys typeFuncs)
+      lookupType ty =
+        case Map.lookup ty typeMap of
+          Just f -> f
+          Nothing -> error "ToFOF.translate: type not found"
+      scheme1' = scheme1 scheme mono' lookupType
+  funcAxioms <- mapM (funcAxiom scheme1') funcs
+  typeAxioms <- mapM (typeAxiom scheme1') tys
+  let axioms =
+        map (simplify . ForAll . bind) . split . simplify . foldr (/\) true $
+          funcAxioms ++ typeAxioms
+  return $
+    [ Input ("types" ++ show i) Axiom axiom | (axiom, i) <- zip axioms [1..] ] ++
+    map (guard scheme1' mono') inps
+
+translate scheme mono f =
+  let f' =
+        Form.run f $ \inps -> do
+          forM inps $ \(Input tag kind f) -> do
+            let prepare f = fmap (foldr (/\) true) (run (withName tag (removeEquiv (simplify f))))
+            fmap (Input tag kind) $
+              case kind of
+                Axiom -> prepare f
+                Conjecture -> fmap notInwards (prepare (nt f))
+      typeI = Type (name "$i") (Finite 0) Infinite
+  in Form.run (translate1 scheme mono f') (return . mapType (const typeI))
+
+-- Typing functions.
+
+tagsFlags :: OptionParser Bool
+tagsFlags =
+  bool "more-axioms"
+    ["Add extra typing axioms for function arguments,",
+     "when using typing tags.",
+     "These are unnecessary for completeness but may help (or hinder!) the prover."]
+
+tags :: Bool -> Scheme
+tags moreAxioms = Scheme
+  { makeFunction = \ty ->
+      newFunction ("to_" ++ base ty) [ty] ty,
+    scheme1 = tags1 moreAxioms }
+
+tags1 :: Bool -> (Type -> Bool) -> (Type -> Function) -> Scheme1
+tags1 moreAxioms mono fs = Scheme1
+  { forAll = ForAll,
+    exists = \(Bind vs f) ->
+       let bound = foldr (/\) true (map guard (Set.toList vs))
+           guard v | mono (typ v) = true
+                   | otherwise = Literal (Pos (fs (typ v) :@: [Var v] :=: Var v))
+       in Exists (Bind vs (simplify bound /\ f)),
+    equals =
+      \t u ->
+        let protect t@Var{} = fs (typ t) :@: [t]
+            protect t = t
+        in Literal (Pos (protect t :=: protect u)),
+    funcAxiom = tagsAxiom moreAxioms mono fs,
+    typeAxiom = \ty -> if moreAxioms then tagsAxiom False mono fs (fs ty) else tagsExists mono ty (fs ty) }
+
+tagsAxiom :: Bool -> (Type -> Bool) -> (Type -> Function) -> Function -> NameM Form
+tagsAxiom moreAxioms mono fs f@(_ ::: FunType args _res) = do
+  vs <- forM args $ \ty ->
+    fmap Var (newSymbol "X" ty)
+  let t = f :@: vs
+      at n f xs = take n xs ++ [f (xs !! n)] ++ drop (n+1) xs
+      tag t = fs (typ t) :@: [t]
+      equate (ty, t') | mono ty = true
+                      | otherwise = t `eq` t'
+      t `eq` u | typ t == O = Literal (Pos (Tru t)) `Equiv` Literal (Pos (Tru u))
+               | otherwise = Literal (Pos (t :=: u))
+      ts = (typ t, tag t):
+           [ (typ (vs !! n), f :@: at n tag vs)
+           | moreAxioms,
+             n <- [0..length vs-1] ]
+  return (foldr (/\) true (map equate ts))
+
+tagsExists :: (Type -> Bool) -> Type -> Function -> NameM Form
+tagsExists mono ty f
+  | mono ty = return true
+  | otherwise = do
+      v <- fmap Var (newSymbol "X" ty)
+      return (Exists (bind (Literal (Pos (f :@: [v] :=: v)))))
+
+-- Typing predicates.
+
+guards :: Scheme
+guards = Scheme
+  { makeFunction = \ty ->
+      newFunction ("is_" ++ base ty) [ty] O,
+    scheme1 = guards1 }
+
+guards1 :: (Type -> Bool) -> (Type -> Function) -> Scheme1
+guards1 mono ps = Scheme1
+  { forAll = \(Bind vs f) ->
+       let bound = foldr (/\) true (map guard (Set.toList vs))
+           guard v | mono (typ v) = true
+                   | not (naked True v f) = true
+                   | otherwise = Literal (Pos (Tru (ps (typ v) :@: [Var v])))
+       in ForAll (Bind vs (simplify (Not bound) \/ f)),
+    exists = \(Bind vs f) ->
+       let bound = foldr (/\) true (map guard (Set.toList vs))
+           guard v | mono (typ v) = true
+--                   | not (naked True v f) = true
+                   | otherwise = Literal (Pos (Tru (ps (typ v) :@: [Var v])))
+       in Exists (Bind vs (simplify bound /\ f)),
+    equals = \t u -> Literal (Pos (t :=: u)),
+    funcAxiom = guardsAxiom mono ps,
+    typeAxiom = guardsTypeAxiom mono ps }
+
+naked :: Symbolic a => Bool -> Variable -> a -> Bool
+naked pos v f
+  | Form <- typeOf f,
+    Not f' <- f = naked (not pos) v f'
+  | Signed <- typeOf f,
+    Pos f' <- f = naked pos v f'
+  | Signed <- typeOf f,
+    Neg f' <- f = naked (not pos) v f'
+  | Atomic <- typeOf f,
+    t :=: u <- f,
+    pos = t == Var v || u == Var v
+  | Bind_ <- typeOf f,
+    Bind vs f' <- f = not (Set.member v vs) && naked pos v f'
+  | otherwise = getAny (collect (Any . naked pos v) f)
+
+guardsAxiom :: (Type -> Bool) -> (Type -> Function) -> Function -> NameM Form
+guardsAxiom mono ps f@(_ ::: FunType args res)
+  | mono res = return true
+  | otherwise = do
+    vs <- forM args $ \ty ->
+      fmap Var (newSymbol "X" ty)
+    return (Literal (Pos (Tru (ps res :@: [f :@: vs]))))
+
+guardsTypeAxiom :: (Type -> Bool) -> (Type -> Function) -> Type -> NameM Form
+guardsTypeAxiom mono ps ty
+  | mono ty = return true
+  | otherwise = do
+    v <- fmap Var (newSymbol "X" ty)
+    return (Exists (bind (Literal (Pos (Tru (ps ty :@: [v]))))))
diff --git a/src/Jukebox/Name.hs b/src/Jukebox/Name.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/Name.hs
@@ -0,0 +1,95 @@
+{-# LANGUAGE TypeOperators, GeneralizedNewtypeDeriving, FlexibleInstances #-}
+module Jukebox.Name where
+
+import Control.Monad
+import Control.Monad.Trans.State.Strict
+import Data.Ord
+import Data.Int
+import Data.Symbol
+import Data.Char
+
+data Name =
+    Fixed {-# UNPACK #-} !Symbol
+  | Unique {-# UNPACK #-} !Int64 String Renamer
+
+type Renamer = String -> Int -> Renaming
+data Renaming = Renaming [String] String
+
+base :: Named a => a -> String
+base x =
+  case name x of
+    Fixed xs -> unintern xs
+    Unique _ xs _ -> xs
+
+renamer :: Named a => a -> Renamer
+renamer x =
+  case name x of
+    Fixed _ -> defaultRenamer
+    Unique _ _ f -> f
+
+defaultRenamer :: Renamer
+defaultRenamer xs 0 = Renaming [] xs
+defaultRenamer xs n = Renaming [] $ xs ++ sep ++ show (n+1)
+  where
+    sep
+      | not (null xs) && isDigit (last xs) = "_"
+      | otherwise = ""
+
+withRenamer :: Name -> Renamer -> Name
+Fixed x `withRenamer` _ = Fixed x
+Unique n xs _ `withRenamer` f = Unique n xs f
+
+instance Eq Name where
+  x == y = compareName x == compareName y
+
+instance Ord Name where
+  compare = comparing compareName
+
+compareName :: Name -> Either Symbol Int64
+compareName (Fixed xs) = Left xs
+compareName (Unique n _ _) = Right n
+
+instance Show Name where
+  show (Fixed xs) = unintern xs
+  show (Unique n xs f) = ys ++ "@" ++ show n
+    where
+      Renaming _ ys = f xs 0
+
+class Named a where
+  name :: a -> Name
+
+instance Named [Char] where
+  name = Fixed . intern
+
+instance Named Name where
+  name = id
+
+data a ::: b = a ::: b deriving Show
+
+lhs :: (a ::: b) -> a
+lhs (x ::: _) = x
+
+rhs :: (a ::: b) -> b
+rhs (_ ::: y) = y
+
+instance Named a => Eq (a ::: b) where s == t = name s == name t
+instance Named a => Ord (a ::: b) where compare = comparing name
+
+instance Named a => Named (a ::: b) where
+  name (a ::: _) = name a
+
+newtype NameM a =
+  NameM { unNameM :: State Int64 a }
+    deriving (Functor, Applicative, Monad)
+
+runNameM :: [Name] -> NameM a -> a
+runNameM xs m =
+  evalState (unNameM m) (maximum (0:[ succ n | Unique n _ _ <- xs ]))
+
+newName :: Named a => a -> NameM Name
+newName x = NameM $ do
+  idx <- get
+  let idx' = idx+1
+  when (idx' < 0) $ error "Name.newName: too many names"
+  put $! idx'
+  return $! Unique idx' (base x) (renamer x)
diff --git a/src/Jukebox/Options.hs b/src/Jukebox/Options.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/Options.hs
@@ -0,0 +1,356 @@
+{-# LANGUAGE FlexibleContexts #-}
+module Jukebox.Options where
+
+import Control.Arrow((***))
+import Control.Monad(mplus)
+import Data.Char
+import Data.List
+import System.Environment
+import System.Exit
+import System.IO
+
+----------------------------------------------------------------------
+-- A parser of some kind annotated with a help text of some kind
+data Annotated d p a = Annotated
+  { descr :: d,
+    parser :: p a }
+
+instance Functor p => Functor (Annotated d p) where
+  fmap f (Annotated d x) = Annotated d (fmap f x)
+
+instance (Monoid d, Applicative p) => Applicative (Annotated d p) where
+  pure = Annotated mempty . pure
+  Annotated d f <*> Annotated d' x =
+    Annotated (d `mappend` d') (f <*> x)
+
+instance (Monoid d, Monoid (p a)) => Monoid (Annotated d p a) where
+  mempty = Annotated mempty mempty
+  Annotated d p `mappend` Annotated d' p' =
+    Annotated (d `mappend` d') (p `mappend` p')
+
+----------------------------------------------------------------------
+-- Parsing of single arguments (e.g. integers)
+-- and single flags (e.g. --verbosity 3).
+
+type ArgParser = Annotated ArgDesc SeqParser
+type ArgDesc = String -- description, e.g. "<number>"
+
+-- Called SeqParser because <*> is sequential composition.
+data SeqParser a = SeqParser
+  { args :: Int, -- How many arguments will be consumed
+    consume :: [String] -> Either Error a }
+
+instance Functor SeqParser where
+  fmap f (SeqParser a c) = SeqParser a (fmap f . c)
+
+instance Applicative SeqParser where
+  pure = SeqParser 0 . const . pure
+  SeqParser a c <*> SeqParser a' c' = SeqParser (a + a') f
+    where f xs = c xs <*> c' (drop a xs)
+
+arg :: ArgDesc -> String -> (String -> Maybe a) -> ArgParser a
+arg desc err f = Annotated desc (SeqParser 1 c)
+  where c [] = Left (Mistake err)
+        c (x:_) | "--" `isPrefixOf` x = Left (Mistake err)
+        c (x:_) =
+          case f x of
+            Nothing -> Left (Mistake err)
+            Just ok -> Right ok
+
+argNum :: (Read a, Num a) => ArgParser a
+argNum = arg "<num>" "expected a number" f
+  where f x =
+          case reads x of
+            [(y, "")] -> Just y
+            _ -> Nothing
+
+argFile :: ArgParser FilePath
+argFile = arg "<file>" "expected a file" Just
+
+argFiles :: ArgParser [FilePath]
+argFiles = arg "<files>" "expected a list of files" $ \x ->
+  Just $ elts $ x ++ ","
+  where
+    elts [] = []
+    elts s  = w:elts r
+      where
+        w = takeWhile (/= ',') s
+        r = tail (dropWhile (/= ',') s)
+
+argName :: ArgParser FilePath
+argName = arg "<name>" "expected a name" Just
+
+argNums :: ArgParser [Int]
+argNums = arg "<nums>" "expected a number list" $ \x ->
+  nums . groupBy (\x y -> isDigit x == isDigit y) $ x ++ ","
+  where
+    nums []                = Just []
+    nums (n:",":ns)        = (read n :) `fmap` nums ns
+    nums (n:"..":m:",":ns) = ([read n .. read m] ++) `fmap` nums ns
+    nums _                 = Nothing
+
+argOption :: [String] -> ArgParser String
+argOption as = arg ("<" ++ concat (intersperse " | " as) ++ ">") "expected an argument" elts
+  where
+    elts x | x `elem` as = Just x
+           | otherwise   = Nothing
+
+argList :: [String] -> ArgParser [String]
+argList as = arg ("<" ++ concat (intersperse " | " as) ++ ">*") "expected an argument" $ \x ->
+  elts $ x ++ ","
+  where
+    elts []              = Just []
+    elts s | w `elem` as = (w:) `fmap` elts r
+      where
+        w = takeWhile (/= ',') s
+        r = tail (dropWhile (/= ',') s)
+    
+    elts _ = Nothing
+
+-- A parser that always fails but produces an error message (useful for --help etc.)
+argUsage :: ExitCode -> [String] -> ArgParser a
+argUsage code err = Annotated [] (SeqParser 0 (const (Left (Usage code err))))
+
+----------------------------------------------------------------------
+-- Parsing of whole command lines.
+
+type OptionParser = Annotated [Flag] ParParser
+
+-- Called ParParser because <*> is parallel composition.
+-- In other words, in f <*> x, f and x both see the whole command line.
+-- We want this when parsing command lines because
+-- it doesn't matter what order we write the options in.
+data ParParser a = ParParser
+  { val :: IO a, -- impure so we can put system information in our options records
+    peek :: [String] -> ParseResult a }
+
+data ParseResult a
+    -- Yes n x: consumed n arguments, continue parsing with x
+  = Yes Int (ParParser a)
+    -- No x: didn't understand this flag, continue parsing with x
+  | No (ParParser a)
+    -- Error
+  | Error Error
+
+data Error =
+    Mistake String
+  | Usage ExitCode [String]
+
+instance Functor ParParser where
+  fmap f x = pure f <*> x
+
+instance Applicative ParParser where
+  pure x = ParParser (return x) (const (pure x))
+  ParParser v p <*> ParParser v' p' =
+    ParParser (v <*> v') (\xs -> p xs <*> p' xs)
+
+instance Functor ParseResult where
+  fmap f x = pure f <*> x
+
+instance Applicative ParseResult where
+  pure = No . pure
+  Yes n r <*> Yes n' r'
+    | n == n' = Yes n (r <*> r')
+    | otherwise = error "Options.ParseResult: inconsistent number of arguments"
+  Error s <*> _ = Error s
+  _ <*> Error s = Error s
+  Yes n r <*> No x = Yes n (r <*> x)
+  No x <*> Yes n r = Yes n (x <*> r)
+  No f <*> No x = No (f <*> x)
+
+runPar :: ParParser a -> [String] -> Either Error (IO a)
+runPar p [] = Right (val p)
+runPar p xs@(x:_) =
+  case peek p xs of
+    Yes n p' -> runPar p' (drop n xs)
+    No _ -> Left (Mistake ("Didn't recognise option " ++ x))
+    Error err -> Left err
+
+awaitP :: (String -> Bool) -> a -> (String -> [String] -> ParseResult a) -> ParParser a
+awaitP p def par = ParParser (return def) f
+  where f (x:xs) | p x =
+          case par x xs of
+            Yes n r -> Yes (n+1) r
+            No _ ->
+              error "Options.await: got No"
+            Error err -> Error err
+        f _ = No (awaitP p def par)
+
+await :: String -> a -> ([String] -> ParseResult a) -> ParParser a
+await flag def f = awaitP (\x -> "--" ++ flag == x) def (const f)
+
+data Flag = Flag
+  { flagName :: String,
+    flagGroup :: String,
+    flagHelp :: [String],
+    flagArgs :: String } deriving (Eq, Show)
+
+-- From a flag name and and argument parser, produce an OptionParser.
+flag :: String -> [String] -> a -> ArgParser a -> OptionParser a
+flag name help def (Annotated desc (SeqParser args f)) =
+  Annotated [desc'] (await name def g)
+  where desc' = Flag name "Common options" help desc
+        g xs =
+          case f xs of
+            Left (Mistake err) -> Error (Mistake ("Error in option --" ++ name ++ ": " ++ err))
+            Left (Usage code err) -> Error (Usage code err)
+            Right y -> Yes args (pure y <* noFlag)
+        -- Give an error if the flag is repeated.
+        noFlag =
+          await name ()
+            (const (Error (Mistake ("Option --" ++ name ++ " occurred twice"))))
+
+manyFlags :: String -> [String] -> ArgParser a -> OptionParser [a]
+manyFlags name help (Annotated desc (SeqParser args f)) =
+  fmap reverse (Annotated [desc'] (go []))
+  where desc' = Flag name "Common options" help desc
+        go xs = await name xs (g xs)
+        g xs ys =
+          case f ys of
+            Left (Mistake err) -> Error (Mistake ("Error in option --" ++ name ++ ": " ++ err))
+            Left (Usage code err) -> Error (Usage code err)
+            Right x -> Yes args (go (x:xs))
+
+-- Read filenames from the command line.
+filenames :: OptionParser [String]
+filenames = Annotated [] (from [])
+  where from xs = awaitP p xs (f xs)
+        p x = not ("--" `isPrefixOf` x)
+        f xs y _ = Yes 0 (from (xs ++ [y]))
+
+-- Take a value from the environment.
+io :: IO a -> OptionParser a
+io m = Annotated [] p
+  where p = ParParser m (const (No p))
+
+-- A boolean flag.
+bool :: String -> [String] -> OptionParser Bool
+bool name help = flag name help False (pure True)
+
+inGroup :: String -> OptionParser a -> OptionParser a
+inGroup x (Annotated fls f) = Annotated [fl{ flagGroup = x } | fl <- fls] f
+
+----------------------------------------------------------------------
+-- Selecting a particular tool.
+
+type ToolParser = Annotated [Tool] PrefixParser
+data Tool = Tool
+  { toolProgName :: String,
+    toolName :: String,
+    toolVersion :: String,
+    toolHelp :: String }
+
+newtype PrefixParser a = PrefixParser (String -> Maybe (Tool, ParParser a))
+
+instance Functor PrefixParser where
+  fmap f (PrefixParser g) = PrefixParser (fmap (id *** fmap f) . g)
+
+instance Monoid (PrefixParser a) where
+  mempty = PrefixParser (const Nothing)
+  PrefixParser f `mappend` PrefixParser g =
+    PrefixParser (\xs -> f xs `mplus` g xs)
+
+runPref :: PrefixParser a -> [String] -> Either Error (IO a)
+runPref _ [] = Left (Mistake "Expected a tool name")
+runPref (PrefixParser f) (x:xs) =
+  case f x of
+    Nothing -> Left (Mistake ("No such tool " ++ x))
+    Just (t, p) ->
+      case runPar p xs of
+        Left (Mistake x) -> Left (Usage (ExitFailure 1) (argError t x))
+        Left (Usage code x) -> Left (Usage code x)
+        Right x -> Right x
+
+tool :: Tool -> OptionParser a -> ToolParser a
+tool t p =
+  Annotated [t] (PrefixParser f)
+  where f x | x == toolProgName t = Just (t, parser p')
+        f _ = Nothing
+        p' = p <* versionParser <* helpParser
+        helpParser = flag "help" ["Show this help text."] () (argUsage ExitSuccess (help t p'))
+        versionParser = flag "version" ["Print the version number."] () (argUsage ExitSuccess [greeting t])
+
+-- Use the program name as a tool name if possible.
+getEffectiveArgs :: ToolParser a -> IO [String]
+getEffectiveArgs (Annotated tools _) = do
+  progName <-
+    case tools of
+      [tool] -> return (toolProgName tool)
+      _ -> getProgName
+  args <- getArgs
+  if progName `elem` map toolProgName tools
+    then return (progName:args)
+    else return args
+
+parseCommandLine :: Tool -> ToolParser a -> IO a
+parseCommandLine t p = do
+  let p' =
+        case p of
+          Annotated [_] _ -> p
+          _ -> versionTool t `mappend` helpTool t p `mappend` p
+  args <- getEffectiveArgs p'
+  case runPref (parser p') args of
+    Left (Mistake err) -> printHelp (ExitFailure 1) (argError t err)
+    Left (Usage code err) -> printHelp code err
+    Right x -> x
+
+----------------------------------------------------------------------
+-- Help screens.
+
+printHelp :: ExitCode -> [String] -> IO a
+printHelp code xs = do
+  mapM_ (hPutStrLn stderr ) xs
+  exitWith code
+
+argError :: Tool -> String -> [String]
+argError t err = [
+  greeting t,
+  err ++ ". Try --help."
+  ]
+
+usageTool :: Tool -> String -> [String] -> String -> ToolParser a
+usageTool t0 flag msg bit = tool (Tool flag' flag' flag' "0") p
+  where p = Annotated [] (ParParser (printHelp ExitSuccess msg)
+                                    (const (Error (Usage (ExitFailure 1) msg'))))
+        flag' = "--" ++ flag
+        msg' = [
+          greeting t0,
+          "Didn't expect any arguments after " ++ flag' ++ ".",
+          "Try " ++ toolProgName t0 ++ " <toolname> " ++ flag' ++ " if you want " ++ bit ++ " a particular tool."
+          ]
+
+versionTool :: Tool -> ToolParser a
+versionTool t0 = usageTool t0 "version" [greeting t0] "the version of"
+
+helpTool :: Tool -> ToolParser a -> ToolParser a
+helpTool t0 p = usageTool t0 "help" help "help for"
+  where help = concat [
+          [greeting t0],
+          usage t0 "<toolname> ",
+          ["<toolname> can be any of the following:"],
+          concat [ justify (toolProgName t) [toolHelp t] | t <- descr p ],
+          ["", "Use " ++ toolProgName t0 ++ " <toolname> --help for help on a particular tool."]
+          ]
+
+help :: Tool -> OptionParser a -> [String]
+help t p = concat [
+  [greeting t],
+  usage t "",
+  ["<option> can be any of the following:"],
+  concat [ justify ("--" ++ flagName f ++ " " ++ flagArgs f) (flagHelp f) | f <- nub (descr p) ]
+  ]
+
+greeting :: Tool -> String
+greeting t = toolName t ++ ", version " ++ toolVersion t ++ "."
+
+usage :: Tool -> String -> [String]
+usage t opts = [
+  "Usage: " ++ toolProgName t ++ " " ++ opts ++ "<option>* <file>*",
+  toolHelp t ++ ".",
+  "",
+  "<file> should be in TPTP format.",
+  ""
+  ]
+
+justify :: String -> [String] -> [String]
+justify name help = ["", "  " ++ name] ++ map ("    " ++) help
diff --git a/src/Jukebox/Provers/E.hs b/src/Jukebox/Provers/E.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/Provers/E.hs
@@ -0,0 +1,104 @@
+{-# LANGUAGE GADTs #-}
+module Jukebox.Provers.E where
+
+import Jukebox.Form hiding (tag, Or)
+import Jukebox.Name
+import Jukebox.Options
+import Control.Applicative hiding (Const)
+import Control.Monad
+import Jukebox.Utils
+import Jukebox.TPTP.Parsec hiding (run)
+import Jukebox.TPTP.Parse.Core hiding (newFunction, Term)
+import Jukebox.TPTP.Print
+import Jukebox.TPTP.Lexer hiding (Normal, keyword, Axiom, Var)
+import Data.Maybe
+import qualified Data.Map.Strict as Map
+import Data.Map(Map)
+
+data EFlags = EFlags {
+  eprover :: String,
+  timeout :: Maybe Int,
+  memory :: Maybe Int
+  }
+
+eflags =
+  inGroup "E prover options" $
+  EFlags <$>
+    flag "eprover"
+      ["Path to the E theorem prover.",
+       "Default: eprover"]
+      "eprover"
+      argFile <*>
+    flag "timeout"
+      ["Timeout for E, in seconds.",
+       "Default: (off)"]
+      Nothing
+      (fmap Just argNum) <*>
+    flag "memory"
+      ["Memory limit for E, in megabytes.",
+       "Default: (off)"]
+      Nothing
+      (fmap Just argNum)
+
+-- Work around bug in E answer coding.
+mangleAnswer :: Symbolic a => a -> NameM a
+mangleAnswer t =
+  case typeOf t of
+    Term -> term t
+    _ -> recursivelyM mangleAnswer t
+  where term (f :@: [t]) | base f == "$answer" = do
+          wrap <- newFunction "answer" [typ t] (head (funArgs f))
+          return (f :@: [wrap :@: [t]])
+        term t = recursivelyM mangleAnswer t
+
+runE :: EFlags -> Problem Form -> IO (Either Answer [Term])
+runE flags prob
+  | not (isFof prob) = error "runE: E doesn't support many-typed problems"
+  | otherwise = do
+    (_code, str) <- popen (eprover flags) eflags
+                   (showProblem (run prob mangleAnswer))
+    return (extractAnswer prob str)
+  where eflags = [ "--soft-cpu-limit=" ++ show n | Just n <- [timeout flags] ] ++
+                 ["--memory-limit=" ++ show n | Just n <- [memory flags] ] ++
+                 ["--tstp-in", "--tstp-out", "-tAuto", "-xAuto"] ++
+                 ["-l", "0"]
+
+extractAnswer :: Symbolic a => a -> String -> Either Answer [Term]
+extractAnswer prob str = fromMaybe (Left status) (fmap Right answer)
+  where varMap = Map.fromList [(show (name x), x) | x <- vars prob]
+        funMap = Map.fromList [(show (name x), x) | x <- functions prob]
+        result = lines str
+        status = head $
+          [Satisfiable | "# SZS status Satisfiable" <- result] ++
+          [Satisfiable | "# SZS status CounterSatisfiable" <- result] ++
+          [Unsatisfiable | "# SZS status Unsatisfiable" <- result] ++
+          [Unsatisfiable | "# SZS status Theorem" <- result] ++
+          [NoAnswer Timeout | "# SZS status ResourceOut" <- result] ++
+          [NoAnswer Timeout | "# SZS status Timeout" <- result] ++
+          [NoAnswer Timeout | "# SZS status MemyOut" <- result] ++
+          [NoAnswer GaveUp]
+        answer = listToMaybe $
+          [ parse xs
+          | line <- result
+          , let prefix = "# SZS answers Tuple ["
+                suffix = "|_]"
+                (prefix', mid) = splitAt (length prefix) line
+                (xs, suffix') = splitAt (length mid - length suffix) mid
+          , prefix == prefix'
+          , suffix == suffix' ]
+        parse xs =
+          let toks = scan xs
+          in case run_ parser (UserState initialState toks) of
+            Ok _ ts -> ts
+            _ -> error "runE: couldn't parse result from E"
+        parser =
+          parens (bracks term `sepBy1` punct Or)
+          <|> fmap (:[]) (bracks term)
+        term =
+          fmap (Var . lookup varMap) variable <|>
+          liftM2 (:@:) (fmap (lookup funMap) atom) terms
+        terms =
+          bracks (term `sepBy1` punct Comma)
+          <|> return []
+        lookup :: Ord a => Map String a -> String -> a
+        lookup m x = Map.findWithDefault (error "runE: result from E mentions free names") x m
diff --git a/src/Jukebox/Provers/SPASS.hs b/src/Jukebox/Provers/SPASS.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/Provers/SPASS.hs
@@ -0,0 +1,51 @@
+{-# LANGUAGE GADTs #-}
+module Jukebox.Provers.SPASS where
+
+import Jukebox.Form hiding (tag, Or)
+import Jukebox.Options
+import Jukebox.Utils
+import Jukebox.TPTP.Print
+
+data SPASSFlags =
+  SPASSFlags {
+    spass   :: String,
+    timeout :: Maybe Int,
+    sos     :: Bool }
+
+spassFlags =
+  inGroup "SPASS prover options" $
+  SPASSFlags <$>
+    flag "spass"
+      ["Path to SPASS.",
+       "Default: SPASS"]
+      "SPASS"
+      argFile <*>
+    flag "timeout"
+      ["Timeout in seconds.",
+       "Default: (none)"]
+      Nothing
+      (fmap Just argNum) <*>
+    flag "sos"
+      ["Use set-of-support strategy.",
+       "Default: false"]
+      False
+      (pure True)
+
+runSPASS :: SPASSFlags -> Problem Form -> IO Answer
+runSPASS flags prob
+  | not (isFof prob) = error "runSPASS: SPASS doesn't support many-typed problems"
+  | otherwise = do
+    (_code, str) <- popen (spass flags) spassFlags (showProblem prob)
+    return (extractAnswer str)
+  where
+    spassFlags =
+      ["-TimeLimit=" ++ show n | Just n <- [timeout flags] ] ++
+      ["-SOS" | sos flags] ++
+      ["-TPTP", "-Stdin"]
+
+extractAnswer :: String -> Answer
+extractAnswer result =
+  head $
+    [ Unsatisfiable    | "SPASS beiseite: Proof found." <- lines result ] ++
+    [ Satisfiable      | "SPASS beiseite: Completion found." <- lines result ] ++
+    [ NoAnswer Timeout ]
diff --git a/src/Jukebox/Sat.hs b/src/Jukebox/Sat.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/Sat.hs
@@ -0,0 +1,70 @@
+module Jukebox.Sat
+  ( Solver
+  , newSolver
+  , deleteSolver
+  , Lit, neg
+  , false, true
+  
+  , SatSolver(..)
+  , newLit
+  , addClause
+  , solve
+  , conflict
+  , modelValue
+  , value
+  )
+ where
+
+--------------------------------------------------------------------------------
+
+import MiniSat
+  ( Solver
+  , deleteSolver
+  , Lit(..)
+  , neg
+  )
+
+import qualified MiniSat as M
+
+--------------------------------------------------------------------------------
+
+false, true :: Lit
+true  = MkLit 0
+false = neg true
+
+newSolver :: IO Solver
+newSolver =
+  do s <- M.newSolver
+     x <- M.newLit s
+     if x == false || x == true
+       then do M.addClause s [true]
+               return s
+       else do error "failed to initialize false and true!"
+
+--------------------------------------------------------------------------------
+
+class SatSolver s where
+  getSolver :: s -> Solver
+
+instance SatSolver Solver where
+  getSolver s = s
+
+newLit :: SatSolver s => s -> IO Lit
+newLit s = M.newLit (getSolver s)
+
+addClause :: SatSolver s => s -> [Lit] -> IO ()
+addClause s xs = M.addClause (getSolver s) xs >> return ()
+
+solve :: SatSolver s => s -> [Lit] -> IO Bool
+solve s xs = M.solve (getSolver s) xs
+
+conflict :: SatSolver s => s -> IO [Lit]
+conflict s = M.conflict (getSolver s)
+
+modelValue :: SatSolver s => s -> Lit -> IO (Maybe Bool)
+modelValue s x = M.modelValue (getSolver s) x
+
+value :: SatSolver s => s -> Lit -> IO (Maybe Bool)
+value s x = M.value (getSolver s) x
+
+--------------------------------------------------------------------------------
diff --git a/src/Jukebox/Sat3.hs b/src/Jukebox/Sat3.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/Sat3.hs
@@ -0,0 +1,47 @@
+module Jukebox.Sat3 where
+
+import Jukebox.Sat
+
+--------------------------------------------------------------------------------
+
+data Lit3 = Lit3{ isFalse :: Lit, isTrue :: Lit }
+
+false3, true3, bottom3 :: Lit3
+false3  = Lit3 true false
+true3   = neg3 false3
+bottom3 = Lit3 false false
+
+neg3 :: Lit3 -> Lit3
+neg3 (Lit3 f t) = Lit3 t f
+
+newLit3 :: SatSolver s => s -> IO Lit3
+newLit3 s =
+  do a <- newLit s
+     b <- newLit s
+     addClause s [neg a, neg b]
+     return (Lit3 a b)
+
+newLit2 :: SatSolver s => s -> IO Lit3
+newLit2 s =
+  do a <- newLit s
+     return (Lit3 a (neg a))
+
+--------------------------------------------------------------------------------
+
+modelValue3 :: SatSolver s => s -> Lit3 -> IO (Maybe Bool)
+modelValue3 s = val3 (modelValue s)
+
+value3 :: SatSolver s => s -> Lit3 -> IO (Maybe Bool)
+value3 s = val3 (value s)
+
+val3 :: (Lit -> IO (Maybe Bool)) -> Lit3 -> IO (Maybe Bool)
+val3 get (Lit3 f t) =
+  do mf <- get f
+     case mf of
+       Just True -> do return (Just False)
+       _         -> do mt <- get t
+                       case mt of
+                         Just True -> return (Just True)
+                         _         -> return Nothing
+
+--------------------------------------------------------------------------------
diff --git a/src/Jukebox/SatEq.hs b/src/Jukebox/SatEq.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/SatEq.hs
@@ -0,0 +1,84 @@
+module Jukebox.SatEq where
+
+import Jukebox.Sat
+import Jukebox.Sat3
+
+import Data.IORef
+import Data.Map as M
+
+--------------------------------------------------------------------------------
+
+data SolverEq =
+  SolverEq
+  { satSolver :: Solver
+  , counter   :: IORef Int
+  , table     :: IORef (Map (Elt,Elt) Lit3)
+  , model     :: IORef (Maybe (Map Elt Elt))
+  }
+
+newSolverEq :: Solver -> IO SolverEq
+newSolverEq s =
+  do ctr <- newIORef 0
+     tab <- newIORef M.empty
+     mod <- newIORef Nothing
+     return SolverEq
+       { satSolver = s
+       , counter   = ctr
+       , table     = tab
+       , model     = mod
+       }
+
+instance SatSolver SolverEq where
+  getSolver = satSolver
+
+class SatSolver s => EqSolver s where
+  getSolverEq :: s -> SolverEq
+
+instance EqSolver SolverEq where
+  getSolverEq s = s
+
+--------------------------------------------------------------------------------
+
+newtype Elt = Elt Int
+  deriving ( Eq, Ord )
+
+instance Show Elt where
+  show (Elt k) = "#" ++ show k
+
+newElt :: EqSolver s => s -> IO Elt
+newElt s =
+  do k <- readIORef (counter (getSolverEq s))
+     writeIORef (counter (getSolverEq s)) $! k+1
+     return (Elt k)
+
+equal :: EqSolver s => s -> Elt -> Elt -> IO Lit3
+equal s x y =
+  case x `compare` y of
+    GT -> equal s y x
+    EQ -> return true3
+    LT -> do tab <- readIORef (table (getSolverEq s))
+             case M.lookup (x,y) tab of
+               Just q ->
+                 do return q
+       
+               Nothing ->
+                 do q <- newLit3 s
+                    writeIORef (table (getSolverEq s)) (M.insert (x,y) q tab)
+                    return q
+
+--------------------------------------------------------------------------------
+
+solveEq :: EqSolver s => s -> [Lit] -> IO Bool
+solveEq = undefined
+
+--------------------------------------------------------------------------------
+
+modelRep :: EqSolver s => s -> Elt -> IO (Maybe Elt)
+modelRep s x =
+  do mmod <- readIORef (model (getSolverEq s))
+     return $
+       case mmod of
+         Just mp -> M.lookup x mp
+         Nothing -> Nothing
+
+--------------------------------------------------------------------------------
diff --git a/src/Jukebox/SatMin.hs b/src/Jukebox/SatMin.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/SatMin.hs
@@ -0,0 +1,29 @@
+module Jukebox.SatMin where
+
+import Jukebox.Sat
+
+solveLocalMin :: SatSolver s => s -> [Lit] -> [Lit] -> IO Bool
+solveLocalMin s as ms =
+  do b <- solve s as
+     if b then do l <- newLit s -- used as a local assumption for this minimization
+                  localMin s as l ms
+                  addClause s [neg l]
+                  return True
+          else do return False
+
+localMin :: SatSolver s => s -> [Lit] -> Lit -> [Lit] -> IO ()
+localMin s as l ms =
+  do -- find out the current values of the m's
+     bs <- sequence [ modelValue s m | m <- ms ]
+  
+     -- assert that all false m's should stay false
+     sequence_ [ addClause s [neg l, neg m] | (m,b) <- ms `zip` bs, b /= Just True ]
+     
+     -- assert that at least one true m should become false also
+     let ms1 = [ m | (m,Just True)  <- ms `zip` bs ]
+     addClause s (neg l : [ neg m | m <- ms1 ])
+     
+     -- is there still a solution?
+     b <- solve s (l:as)
+     if b then localMin s as l ms1
+          else return ()
diff --git a/src/Jukebox/TPTP/FindFile.hs b/src/Jukebox/TPTP/FindFile.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/TPTP/FindFile.hs
@@ -0,0 +1,38 @@
+module Jukebox.TPTP.FindFile where
+
+import System.FilePath
+import System.Directory(doesFileExist)
+import System.Environment
+import Control.Exception
+import Control.Monad
+import Jukebox.Options
+
+findFile :: [FilePath] -> FilePath -> IO (Maybe FilePath)
+findFile [] _file = return Nothing
+findFile (path:paths) file = do
+  let candidate = path </> file
+  exists <- doesFileExist candidate
+  if exists then return (Just candidate)
+   else findFile paths file
+
+findFileTPTP :: [FilePath] -> FilePath -> IO (Maybe FilePath)
+findFileTPTP dirs file = do
+  let candidates = [file, "Problems" </> file,
+                    "Problems" </> take 3 file </> file]
+  fmap msum (mapM (findFile dirs) candidates)
+
+getTPTPDirs :: IO [FilePath]
+getTPTPDirs = do { dir <- getEnv "TPTP"; return [dir] } `catch` f
+  where f :: IOException -> IO [FilePath]
+        f _ = return []
+
+findFileFlags =
+  concat <$>
+  sequenceA [
+    pure ["."],
+    flag "root"
+      ["Extra directories that will be searched for TPTP input files."]
+      []
+      argFiles,
+    io getTPTPDirs
+    ]
diff --git a/src/Jukebox/TPTP/Lexer.x b/src/Jukebox/TPTP/Lexer.x
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/TPTP/Lexer.x
@@ -0,0 +1,204 @@
+-- -*- mode: haskell -*-
+
+-- Roughly taken from the TPTP syntax reference
+{
+{-# OPTIONS_GHC -O2 -fno-warn-deprecated-flags #-}
+{-# LANGUAGE BangPatterns #-}
+module Jukebox.TPTP.Lexer(
+  scan,
+  Pos(..),
+  Token(..),
+  Punct(..),
+  Defined(..),
+  Keyword(..),
+  TokenStream(..),
+  Contents(..)) where
+
+import Data.Word
+import Data.Char
+}
+
+$alpha = [a-zA-Z0-9_]
+$anything = [. \n]
+@quoted = ($printable # [\\']) | \\ $printable
+@dquoted = ($printable # [\\\"]) | \\ $printable
+
+tokens :-
+-- Comments and whitespace
+"%" .* ;
+"/*" (($anything # \*)* "*"+
+      ($anything # [\/\*]))*
+     ($anything # \*)* "*"* "*/" ; -- blech!
+$white+ ;
+
+-- Keywords.
+"thf" { k Thf }
+"tff" { k Tff }
+"fof" { k Fof }
+"cnf" { k Cnf }
+"axiom" { k Axiom }
+"hypothesis" { k Hypothesis }
+"definition" { k Definition }
+"assumption" { k Assumption }
+"lemma" { k Lemma }
+"theorem" { k Theorem }
+"conjecture" { k Conjecture }
+"negated_conjecture" { k NegatedConjecture }
+"question" { k Question }
+"plain" { k Plain }
+"fi_domain" { k FiDomain }
+"fi_hypothesis" { k FiHypothesis }
+"fi_predicates" { k FiPredicates }
+"type" { k Type }
+"unknown" { k Unknown }
+"include" { k Include }
+-- Defined symbols.
+"$true" { d DTrue }
+"$false" { d DFalse }
+"$equal" { d DEqual }
+"$distinct" { d DDistinct }
+"$itef" { d DItef }
+"$itett" | "$itetf" { d DItet }
+"$o" | "$oType" { d DO }
+"$i" | "$iType" { d DI }
+"$tType" { d DTType }
+-- Atoms.
+"$"{0,2} [a-z] $alpha* { Atom Normal . copy }
+-- Atoms with funny quoted names (here we diverge from the official
+-- syntax, which only allows the escape sequences \\ and \' in quoted
+-- atoms: we allow \ to be followed by any printable character)
+"'"  @quoted+ "'" { Atom Normal . unquote }
+-- Vars are easy :)
+[A-Z][$alpha]* { Var . copy }
+-- Distinct objects, which are double-quoted
+\" @dquoted+  \" { DistinctObject . unquote }
+-- Integers
+[\+\-]? (0 | [1-9][0-9]*)/($anything # $alpha) { Number . read }
+
+-- Operators (FOF)
+"("  { p LParen }  ")"   { p RParen }  "["  { p LBrack }   "]"  { p RBrack }
+","  { p Comma }   "."   { p Dot }     "|"  { p Or }       "&"  { p And }
+"~"  { p Not }     "<=>" { p Iff }     "=>" { p Implies }  "<=" { p Follows }
+"<~>"{ p Xor }     "~|"  { p Nor }     "~&" { p Nand }     "="  { p Eq }
+"!=" { p Neq }     "!"   { p ForAll }  "?"  { p Exists }   ":=" { p Let }
+":-" { p LetTerm }
+-- Operators (TFF)
+":" { p Colon }    "*"   { p Times }   "+"  { p Plus }     ">"  { p FunArrow }
+-- Operators (THF)
+"^"  { p Lambda } "@" { p Apply }  "!!" { p ForAllLam }  "??"  { p ExistsLam }
+"@+" { p Some }   "@-" { p The }   "<<" { p Subtype }    "-->" { p SequentArrow }
+"!>" { p DependentProduct }        "?*" { p DependentSum }
+
+{
+data Pos = Pos {-# UNPACK #-} !Word {-# UNPACK #-} !Word deriving Show
+data Token = Atom { keyword :: !Keyword, tokenName :: !String }
+           | Defined { defined :: !Defined  }
+           | Var { tokenName :: !String }
+           | DistinctObject { tokenName :: !String }
+           | Number { value :: !Integer }
+           | Punct { kind :: !Punct }
+           | Eof
+           | Error
+
+data Keyword = Normal
+             | Thf | Tff | Fof | Cnf
+             | Axiom | Hypothesis | Definition | Assumption
+             | Lemma | Theorem | Conjecture | NegatedConjecture | Question
+             | Plain | FiDomain | FiHypothesis | FiPredicates | Type | Unknown
+             | Include deriving (Eq, Ord)
+
+instance Show Keyword where
+  show x =
+    case x of {
+      Normal -> "normal";
+      Thf -> "thf"; Tff -> "tff"; Fof -> "fof"; Cnf -> "cnf";
+      Axiom -> "axiom"; Hypothesis -> "hypothesis"; Definition -> "definition";
+      Assumption -> "assumption"; Lemma -> "lemma"; Theorem -> "theorem";
+      Conjecture -> "conjecture"; NegatedConjecture -> "negated_conjecture";
+      Question -> "question"; Plain -> "plain"; FiDomain -> "fi_domain";
+      FiHypothesis -> "fi_hypothesis"; FiPredicates -> "fi_predicates";
+      Type -> "type"; Unknown -> "unknown"; Include -> "include" }
+
+-- We only include defined names that need special treatment from the
+-- parser here: you can freely make up any other names starting with a
+-- '$' and they get turned into Atoms.
+data Defined = DTrue | DFalse | DEqual | DDistinct | DItef | DItet
+             | DO | DI | DTType deriving (Eq, Ord)
+
+instance Show Defined where
+  show x =
+    case x of {
+      DTrue -> "$true"; DFalse -> "$false"; DEqual -> "$equal";
+      DDistinct -> "$distinct"; DItef -> "$itef"; DItet -> "$itet";
+      DO -> "$o"; DI -> "$i"; DTType -> "$tType" }
+
+data Punct = LParen | RParen | LBrack | RBrack | Comma | Dot
+           | Or | And | Not | Iff | Implies | Follows | Xor | Nor | Nand
+           | Eq | Neq | ForAll | Exists | Let | LetTerm -- FOF
+           | Colon | Times | Plus | FunArrow -- TFF
+           | Lambda | Apply | ForAllLam | ExistsLam
+           | DependentProduct | DependentSum | Some | The
+           | Subtype | SequentArrow -- THF
+             deriving (Eq, Ord)
+
+instance Show Punct where
+  show x =
+    case x of {
+      LParen -> "("; RParen -> ")"; LBrack -> "["; RBrack -> "]";
+      Comma -> ","; Dot -> "."; Or -> "|"; And -> "&"; Not -> "~";
+      Iff -> "<=>"; Implies -> "=>"; Follows -> "<="; Xor -> "<~>";
+      Nor -> "~|"; Nand -> "~&"; Eq -> "="; Neq -> "!="; ForAll -> "!";
+      Exists -> "?"; Let -> ":="; Colon -> ":"; Times -> "*"; Plus -> "+";
+      FunArrow -> ">"; Lambda -> "^"; Apply -> "@"; ForAllLam -> "!!";
+      ExistsLam -> "??"; Some -> "@+"; The -> "@-"; Subtype -> "<<";
+      SequentArrow -> "-->"; DependentProduct -> "!>"; DependentSum -> "?*";
+      LetTerm -> ":-" }
+
+p x = const (Punct x)
+k x = Atom x . copy
+d x = const (Defined x)
+
+copy :: String -> String
+copy = id
+
+unquote :: String -> String
+unquote (_:x)
+  | null z = init y
+  | otherwise = y ++ [z !! 1] ++ unquote (drop 2 z)
+  where (y, z) = break (== '\\') x
+    
+-- The main scanner function, heavily modified from Alex's posn-bytestring wrapper.
+
+data TokenStream = At {-# UNPACK #-} !Pos !Contents
+data Contents = Cons !Token TokenStream
+
+scan xs = go (Input (Pos 1 1) '\n' xs)
+  where go inp@(Input pos _ xs) =
+          case alexScan inp 0 of
+                AlexEOF -> let t = At pos (Cons Eof t) in t
+                AlexError _ -> let t = At pos (Cons Error t) in t
+                AlexSkip  inp' _ -> go inp'
+                AlexToken inp' len act ->
+                  At pos (act (take len xs) `Cons` go inp')
+
+data AlexInput = Input {-# UNPACK #-} !Pos {-# UNPACK #-} !Char String
+
+alexInputPrevChar :: AlexInput -> Char
+alexInputPrevChar (Input _ c _) = c
+
+{-# INLINE alexGetByte #-}
+alexGetByte :: AlexInput -> Maybe (Word8,AlexInput)
+alexGetByte i = fmap f (alexGetChar i)
+  where f (c, i') = (fromIntegral (ord c), i')
+{-# INLINE alexGetChar #-}
+alexGetChar :: AlexInput -> Maybe (Char,AlexInput)
+alexGetChar (Input p _ (x:xs)) =
+  Just (x, Input (advance p x) x xs)
+alexGetChar _ = Nothing
+
+{-# INLINE advance #-}
+advance :: Pos -> Char -> Pos
+advance (Pos l c) '\t' = Pos  l    (c+8 - (c-1) `mod` 8)
+advance (Pos l _) '\n' = Pos (l+1) 1
+advance (Pos l c) _    = Pos  l    (c+1)
+}
diff --git a/src/Jukebox/TPTP/Parse.hs b/src/Jukebox/TPTP/Parse.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/TPTP/Parse.hs
@@ -0,0 +1,52 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+module Jukebox.TPTP.Parse where
+
+import Jukebox.TPTP.FindFile
+import qualified Jukebox.TPTP.Parse.Core as Parser
+import Control.Monad.IO.Class
+import Control.Monad.Trans.Except
+import Jukebox.Form hiding (Pos, run)
+import Control.Exception
+import Data.List
+import System.IO
+
+parseString :: String -> IO (Problem Form)
+parseString xs =
+  case Parser.parseProblem "<string>" xs of
+    Parser.ParseFailed loc msg ->
+      error ("Parse error at " ++ show loc ++ ":\n" ++ unlines msg)
+    Parser.ParseSucceeded prob ->
+      return prob
+    Parser.ParseStalled loc _ _ ->
+      error ("Include directive found at " ++ show loc)
+
+parseProblem :: [FilePath] -> FilePath -> IO (Either String (Problem Form))
+parseProblem dirs name = parseProblemWith (findFileTPTP dirs) name
+
+parseProblemWith :: (FilePath -> IO (Maybe FilePath)) -> FilePath -> IO (Either String (Problem Form))
+parseProblemWith findFile name =
+  runExceptT $ do
+    file <- readInFile (Parser.Location "<command line>" 0 0) name
+    process (Parser.parseProblem name file)
+
+  where
+    err loc msg = throwE msg'
+      where
+        msg' = "Error in " ++ show loc ++ ":\n" ++ msg
+
+    readInFile pos name = do
+      mfile <- liftIO (findFile name)
+      case mfile of
+        Nothing ->
+          err pos ("File '" ++ name ++ "' not found")
+        Just file ->
+          ExceptT $ do
+            liftIO $ hPutStrLn stderr $ "Reading " ++ file ++ "..."
+            fmap Right (readFile file) `catch`
+              \(e :: IOException) -> return (Left (show e))
+
+    process (Parser.ParseFailed loc msg) = err loc (intercalate "\n" msg)
+    process (Parser.ParseSucceeded prob) = return prob
+    process (Parser.ParseStalled loc name cont) = do
+      file <- readInFile loc name
+      process (cont file)
diff --git a/src/Jukebox/TPTP/Parse/Core.hs b/src/Jukebox/TPTP/Parse/Core.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/TPTP/Parse/Core.hs
@@ -0,0 +1,528 @@
+-- Parse and typecheck TPTP clauses, stopping at include-clauses.
+
+{-# LANGUAGE BangPatterns, MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, TypeOperators, TypeFamilies, CPP, DeriveFunctor #-}
+{-# OPTIONS_GHC -funfolding-use-threshold=1000 #-}
+module Jukebox.TPTP.Parse.Core where
+
+#include "errors.h"
+import Jukebox.TPTP.Parsec
+import Control.Applicative
+import Control.Monad
+import qualified Data.Map.Strict as Map
+import Data.Map(Map)
+import Data.List
+import Jukebox.TPTP.Print
+import Jukebox.Name
+import qualified Data.Set as Set
+import Data.Int
+
+import Jukebox.TPTP.Lexer hiding
+  (Pos, Error, Include, Var, Type, Not, ForAll,
+   Exists, And, Or, Type, Apply, Implies, Follows, Xor, Nand, Nor,
+   keyword, defined, kind)
+import qualified Jukebox.TPTP.Lexer as L
+import qualified Jukebox.Form as Form
+import Jukebox.Form hiding (tag, kind, Axiom, Conjecture, Question, newFunction, TypeOf(..), run)
+import qualified Jukebox.Name as Name
+
+-- The parser monad
+
+data ParseState =
+  MkState ![Input Form]          -- problem being constructed, inputs are in reverse order
+          !(Map String Type)     -- types in scope
+          !(Map String Function) -- functions in scope
+          !(Map String Variable) -- variables in scope, for CNF
+          !Int64                 -- unique supply
+type Parser = Parsec ParsecState
+type ParsecState = UserState ParseState TokenStream
+
+-- An include-clause.
+data IncludeStatement = Include String (Maybe [Tag]) deriving Show
+
+-- The initial parser state.
+initialState :: ParseState
+initialState = initialStateFrom [] Map.empty Map.empty
+
+initialStateFrom :: [Name] -> Map String Type -> Map String (Name ::: FunType) -> ParseState
+initialStateFrom xs tys fs = MkState [] tys fs Map.empty n
+  where
+    n = maximum (0:[succ m | Unique m _ _ <- xs])
+
+instance Stream TokenStream Token where
+  primToken (At _ (Cons Eof _)) _ok err _fatal = err
+  primToken (At _ (Cons L.Error _)) _ok _err fatal = fatal "Lexical error"
+  primToken (At _ (Cons t ts)) ok _err _fatal = ok ts t
+  type Position TokenStream = TokenStream
+  position = id
+
+-- The main parsing function.
+data ParseResult a =
+    ParseFailed Location [String]
+  | ParseSucceeded a
+  | ParseStalled Location FilePath (String -> ParseResult a)
+  deriving Functor
+
+instance Applicative ParseResult where
+  pure = return
+  (<*>) = liftM2 ($)
+
+instance Monad ParseResult where
+  return = ParseSucceeded
+  ParseFailed loc err >>= _ = ParseFailed loc err
+  ParseSucceeded x >>= f = f x
+  ParseStalled loc name k >>= f =
+    ParseStalled loc name (\xs -> k xs >>= f)
+
+data Location = Location FilePath Integer Integer
+instance Show Location where
+  show (Location file row col) =
+    file ++ " (line " ++ show row ++ ", column " ++ show col ++ ")"
+
+makeLocation :: FilePath -> L.Pos -> Location
+makeLocation file (L.Pos row col) =
+  Location file (fromIntegral row) (fromIntegral col)
+
+parseProblem :: FilePath -> String -> ParseResult [Input Form]
+parseProblem name contents = parseProblemFrom initialState name contents
+
+parseProblemFrom :: ParseState -> FilePath -> String -> ParseResult [Input Form]
+parseProblemFrom state name contents =
+  fmap finalise $
+    aux Nothing name (UserState state (scan contents))
+  where
+    aux :: Maybe [Tag] -> FilePath -> ParsecState -> ParseResult ParseState
+    aux tags name state =
+      case run report (section (included tags)) state of
+        (UserState{userStream = At pos _}, Left err) ->
+          ParseFailed (makeLocation name pos) err
+        (UserState{userState = state'}, Right Nothing) ->
+          return state'
+        (UserState state (input'@(At pos _)),
+         Right (Just (Include name' tags'))) ->
+          ParseStalled (makeLocation name pos) name' $ \input -> do
+            state' <- aux (tags `merge` tags') name' (UserState state (scan input))
+            aux tags name (UserState state' input')
+
+    report :: ParsecState -> [String]
+    report UserState{userStream = At _ (Cons Eof _)} =
+      ["Unexpected end of file"]
+    report UserState{userStream = At _ (Cons L.Error _)} =
+      ["Lexical error"]
+    report UserState{userStream = At _ (Cons t _)} =
+      ["Unexpected " ++ show t]
+
+    included :: Maybe [Tag] -> Tag -> Bool
+    included Nothing _ = True
+    included (Just xs) x = x `elem` xs
+
+    merge :: Maybe [Tag] -> Maybe [Tag] -> Maybe [Tag]
+    merge Nothing x = x
+    merge x Nothing = x
+    merge (Just xs) (Just ys) = Just (xs `intersect` ys)
+
+    finalise :: ParseState -> Problem Form
+    finalise (MkState p _ _ _ _) = check (reverse p)
+
+-- Wee function for testing.
+testParser :: Parser a -> String -> Either [String] a
+testParser p s = snd (run (const []) p (UserState initialState (scan s)))
+
+-- Primitive parsers.
+
+{-# INLINE keyword' #-}
+keyword' p = satisfy p'
+  where p' Atom { L.keyword = k } = p k
+        p' _ = False
+{-# INLINE keyword #-}
+keyword k = keyword' (== k) <?> "'" ++ show k ++ "'"
+{-# INLINE punct' #-}
+punct' p = satisfy p'
+  where p' Punct { L.kind = k } = p k
+        p' _ = False
+{-# INLINE punct #-}
+punct k = punct' (== k) <?> "'" ++ show k ++ "'"
+{-# INLINE defined' #-}
+defined' p = fmap L.defined (satisfy p')
+  where p' Defined { L.defined = d } = p d
+        p' _ = False
+{-# INLINE defined #-}
+defined k = defined' (== k) <?> "'" ++ show k ++ "'"
+{-# INLINE variable #-}
+variable = fmap tokenName (satisfy p) <?> "variable"
+  where p L.Var{} = True
+        p _ = False
+{-# INLINE number #-}
+number = fmap value (satisfy p) <?> "number"
+  where p Number{} = True
+        p _ = False
+{-# INLINE atom #-}
+atom = fmap tokenName (keyword' (const True)) <?> "atom"
+
+-- Combinators.
+
+parens, bracks :: Parser a -> Parser a
+{-# INLINE parens #-}
+parens p = between (punct LParen) (punct RParen) p
+{-# INLINE bracks #-}
+bracks p = between (punct LBrack) (punct RBrack) p
+
+-- Build an expression parser from a binary-connective parser
+-- and a leaf parser.
+binExpr :: Parser a -> Parser (a -> a -> Parser a) -> Parser a
+binExpr leaf op = do
+  lhs <- leaf
+  do { f <- op; rhs <- binExpr leaf op; f lhs rhs } <|> return lhs
+
+-- Parsing clauses.
+
+-- Parse as many things as possible until EOF or an include statement.
+section :: (Tag -> Bool) -> Parser (Maybe IncludeStatement)
+section included = skipMany (input included) >> (fmap Just include <|> (eof >> return Nothing))
+
+-- A single non-include clause.
+input :: (Tag -> Bool) -> Parser ()
+input included = declaration Cnf (formulaIn cnf) <|>
+                 declaration Fof (formulaIn fof) <|>
+                 declaration Tff (\tag -> formulaIn tff tag <|> typeDeclaration)
+  where {-# INLINE declaration #-}
+        declaration k m = do
+          keyword k
+          parens $ do
+            t <- tag
+            punct Comma
+            -- Don't bother typechecking clauses that we are not
+            -- supposed to include in the problem (seems in the
+            -- spirit of TPTP's include mechanism)
+            if included t then m t else balancedParens
+          punct Dot
+          return ()
+        formulaIn lang tag = do
+          k <- kind
+          punct Comma
+          form <- lang
+          newFormula (k tag form)
+        balancedParens = skipMany (parens balancedParens <|> (satisfy p >> return ()))
+        p Punct{L.kind=LParen} = False
+        p Punct{L.kind=RParen} = False
+        p _ = True
+
+-- A TPTP kind.
+kind :: Parser (Tag -> Form -> Input Form)
+kind = axiom Axiom <|> axiom Hypothesis <|> axiom Definition <|>
+       axiom Assumption <|> axiom Lemma <|> axiom Theorem <|>
+       general Conjecture Form.Conjecture <|>
+       general NegatedConjecture Form.Axiom <|>
+       general Question Form.Question
+  where axiom t = general t Form.Axiom
+        general k kind = keyword k >> return (mk kind)
+        mk kind tag form =
+          Input { Form.tag = tag,
+                  Form.kind = kind,
+                  Form.what = form }
+
+-- A formula name.
+tag :: Parser Tag
+tag = atom <|> fmap show number <?> "clause name"
+
+-- An include declaration.
+include :: Parser IncludeStatement
+include = do
+  keyword L.Include
+  res <- parens $ do
+    name <- atom <?> "quoted filename"
+    clauses <- do { punct Comma
+                  ; fmap Just (bracks (sepBy1 tag (punct Comma))) } <|> return Nothing
+    return (Include name clauses)
+  punct Dot
+  return res
+
+-- Inserting types, functions and clauses.
+
+newFormula :: Input Form -> Parser ()
+newFormula input = do
+  MkState p t f v n <- getState
+  putState (MkState (input:p) t f v n)
+  
+newFunction :: String -> FunType -> Parser (Name ::: FunType)
+newFunction name ty' = do
+  f@(_ ::: ty) <- lookupFunction ty' name
+  unless (ty == ty') $ do
+    fatalError $ "Constant " ++ name ++
+                 " was declared to have type " ++ prettyShow ty' ++
+                 " but already has type " ++ prettyShow ty
+  return f
+
+{-# INLINE applyFunction #-}
+applyFunction :: String -> [Term] -> Type -> Parser Term
+applyFunction name args' res = do
+  f@(_ ::: ty) <- lookupFunction (FunType (replicate (length args') individual) res) name
+  unless (map typ args' == args ty) $ typeError f args'
+  return (f :@: args')
+
+{-# NOINLINE typeError #-}
+typeError f@(x ::: ty) args' = do
+    let plural 1 x _ = x 
+        plural _ _ y = y
+    fatalError $ "Type mismatch in term '" ++ prettyShow (f :@: args') ++ "': " ++
+                 "Constant " ++ prettyShow x ++
+                 if length (args ty) == length args' then
+                   " has type " ++ prettyShow ty ++
+                   " but was applied to " ++ plural (length args') "an argument" "arguments" ++
+                   " of type " ++ prettyShow (map typ args')
+                 else
+                   " has arity " ++ show (length args') ++
+                   " but was applied to " ++ show (length (args ty)) ++
+                   plural (length (args ty)) " argument" " arguments"
+
+{-# INLINE lookupType #-}
+lookupType :: String -> Parser Type
+lookupType xs = do
+  MkState p t f v n <- getState
+  case Map.lookup xs t of
+    Nothing -> do
+      let ty = Type (name xs) Infinite Infinite
+      putState (MkState p (Map.insert xs ty t) f v n)
+      return ty
+    Just ty -> return ty
+
+{-# INLINE lookupFunction #-}
+lookupFunction :: FunType -> String -> Parser (Name ::: FunType)
+lookupFunction def x = do
+  MkState p t f v n <- getState
+  case Map.lookup x f of
+    Nothing -> do
+      let decl = name x ::: def
+      putState (MkState p t (Map.insert x decl f) v n)
+      return decl
+    Just f -> return f
+
+-- The type $i (anything whose type is not specified gets this type)
+individual :: Type
+individual = Type (name "$i") Infinite Infinite
+
+-- Parsing formulae.
+
+cnf, tff, fof :: Parser Form
+cnf = do
+  MkState p t f _ n <- getState
+  putState (MkState p t f Map.empty n)
+  formula NoQuantification __
+tff = formula Typed Map.empty
+fof = formula Untyped Map.empty
+
+-- We cannot always know whether what we are parsing is a formula or a
+-- term, since we don't have lookahead. For example, p(x) might be a
+-- formula, but in p(x)=y, p(x) is a term.
+--
+-- To deal with this, we introduce the Thing datatype.
+-- A thing is either a term or a formula, or a literal that we don't know
+-- if it should be a term or a formula. Instead of a separate formula-parser
+-- and term-parser we have a combined thing-parser.
+data Thing = Apply !String ![Term]
+           | Term !Term
+           | Formula !Form
+
+instance Show Thing where
+  show (Apply f []) = f
+  show (Apply f args) =
+    f ++
+      case args of
+        [] -> ""
+        args -> prettyShow args
+  show (Term t) = prettyShow t
+  show (Formula f) = prettyShow f
+
+-- However, often we do know whether we want a formula or a term,
+-- and there it's best to use a specialised parser (not least because
+-- the error messages are better). For that reason, our parser is
+-- parametrised on the type of thing you want to parse. We have two
+-- main parsers:
+--   * 'term' parses an atomic expression
+--   * 'formula' parses an arbitrary expression
+-- You can instantiate 'term' for Term, Form or Thing; in each case
+-- you get an appropriate parser. You can instantiate 'formula' for
+-- Form or Thing.
+
+-- Types for which a term f(...) is a valid literal. These are the types on
+-- which you can use 'term'.
+class TermLike a where
+  -- Convert from a Thing.
+  fromThing :: Thing -> Parser a
+  -- Parse a variable occurrence as a term on its own, if that's allowed.
+  var :: Mode -> Map String Variable -> Parser a
+  -- A parser for this type.
+  parser :: Mode -> Map String Variable -> Parser a
+
+data Mode = Typed | Untyped | NoQuantification
+
+instance TermLike Form where
+  {-# INLINE fromThing #-}
+  fromThing (Apply x xs) = fmap (Literal . Pos . Tru) (applyFunction x xs O)
+  fromThing (Term _) = mzero
+  fromThing (Formula f) = return f
+  -- A variable itself is not a valid formula.
+  var _ _ = mzero
+  parser = formula
+
+instance TermLike Term where
+  {-# INLINE fromThing #-}
+  fromThing (Apply x xs) = applyFunction x xs individual
+  fromThing (Term t) = return t
+  fromThing (Formula _) = mzero
+  parser = term
+
+  {-# INLINE var #-}
+  var NoQuantification _ = do
+    x <- variable
+    MkState p t f ctx n <- getState
+    case Map.lookup x ctx of
+      Just v -> return (Var v)
+      Nothing -> do
+        let v = Unique (n+1) x defaultRenamer ::: individual
+        putState (MkState p t f (Map.insert x v ctx) (n+1))
+        return (Var v)
+  var _ ctx = do
+    x <- variable
+    case Map.lookup x ctx of
+      Just v -> return (Var v)
+      Nothing -> fatalError $ "unbound variable " ++ x
+
+instance TermLike Thing where
+  fromThing = return
+  var mode ctx = fmap Term (var mode ctx)
+  parser = formula
+
+-- Types that can represent formulae. These are the types on which
+-- you can use 'formula'.
+class TermLike a => FormulaLike a where
+  fromFormula :: Form -> a
+
+instance FormulaLike Form where fromFormula = id
+instance FormulaLike Thing where fromFormula = Formula
+
+-- An atomic expression.
+{-# INLINEABLE term #-}
+term :: TermLike a => Mode -> Map String Variable -> Parser a
+term mode ctx = function <|> var mode ctx <|> parens (parser mode ctx)
+  where {-# INLINE function #-}
+        function = do
+          x <- atom
+          args <- parens (sepBy1 (term mode ctx) (punct Comma)) <|> return []
+          fromThing (Apply x args)
+
+literal, unitary, quantified, formula ::
+  FormulaLike a => Mode -> Map String Variable -> Parser a
+{-# INLINE literal #-}
+literal mode ctx = true <|> false <|> binary <?> "literal"
+  where {-# INLINE true #-}
+        true = do { defined DTrue; return (fromFormula (And [])) }
+        {-# INLINE false #-}
+        false = do { defined DFalse; return (fromFormula (Or [])) }
+        binary = do
+          x <- term mode ctx :: Parser Thing
+          let {-# INLINE f #-}
+              f p sign = do
+               punct p
+               lhs <- fromThing x :: Parser Term
+               rhs <- term mode ctx :: Parser Term
+               let form = Literal . sign $ lhs :=: rhs
+               when (typ lhs /= typ rhs) $
+                 fatalError $ "Type mismatch in equality '" ++ prettyShow form ++ 
+                              "': left hand side has type " ++ prettyShow (typ lhs) ++
+                              " but right hand side has type " ++ prettyShow (typ rhs)
+               return (fromFormula form)
+          f Eq Pos <|> f Neq Neg <|> fromThing x
+
+{-# INLINEABLE unitary #-}
+unitary mode ctx = negation <|> quantified mode ctx <|> literal mode ctx
+  where {-# INLINE negation #-}
+        negation = do
+          punct L.Not
+          fmap (fromFormula . Not) (unitary mode ctx :: Parser Form)
+
+{-# INLINE quantified #-}
+quantified mode ctx = do
+  q <- (punct L.ForAll >> return ForAll) <|>
+       (punct L.Exists >> return Exists)
+  vars <- bracks (sepBy1 (binder mode) (punct Comma))
+  let ctx' = foldl' (\m v -> Map.insert (Name.base (Name.name v)) v m) ctx vars
+  punct Colon
+  rest <- unitary mode ctx' :: Parser Form
+  return (fromFormula (q (Bind (Set.fromList vars) rest)))
+
+-- A general formula.
+{-# INLINEABLE formula #-}
+formula mode ctx = do
+  x <- unitary mode ctx :: Parser Thing
+  let binop op t u = op [t, u]
+      {-# INLINE connective #-}
+      connective p op = do
+        punct p
+        lhs <- fromThing x
+        rhs <- formula mode ctx :: Parser Form
+        return (fromFormula (op lhs rhs))
+  connective L.And (binop And) <|> connective L.Or (binop Or) <|>
+   connective Iff Equiv <|>
+   connective L.Implies (Connective Implies) <|>
+   connective L.Follows (Connective Follows) <|>
+   connective L.Xor (Connective Xor) <|>
+   connective L.Nor (Connective Nor) <|>
+   connective L.Nand (Connective Nand) <|>
+   fromThing x
+
+binder :: Mode -> Parser Variable
+binder NoQuantification =
+  fatalError "Used a quantifier in a CNF clause"
+binder mode = do
+  x <- variable
+  ty <- do { punct Colon;
+             case mode of {
+               Typed -> return ();
+               Untyped ->
+                 fatalError "Used a typed quantification in an untyped formula" };
+             type_ } <|> return individual
+  MkState p t f v n <- getState
+  putState (MkState p t f v (n+1))
+  return (Unique n x defaultRenamer ::: ty)
+
+-- Parse a type
+type_ :: Parser Type
+type_ =
+  do { x <- atom; lookupType x } <|>
+  do { defined DI; return individual }
+
+-- A little data type to help with parsing types.
+data Type_ = TType | Fun [Type] Type | Prod [Type]
+
+prod :: Type_ -> Type_ -> Parser Type_
+prod (Prod tys) (Prod tys2) | not (O `elem` tys ++ tys2) = return $ Prod (tys ++ tys2)
+prod _ _ = fatalError "invalid type"
+
+arrow :: Type_ -> Type_ -> Parser Type_
+arrow (Prod ts) (Prod [x]) = return $ Fun ts x
+arrow _ _ = fatalError "invalid type"
+
+leaf :: Parser Type_
+leaf = do { defined DTType; return TType } <|>
+       do { defined DO; return (Prod [O]) } <|>
+       do { ty <- type_; return (Prod [ty]) } <|>
+       parens compoundType
+
+compoundType :: Parser Type_
+compoundType = leaf `binExpr` (punct Times >> return prod)
+                    `binExpr` (punct FunArrow >> return arrow)
+
+typeDeclaration :: Parser ()
+typeDeclaration = do
+  keyword L.Type
+  punct Comma
+  let manyParens p = parens (manyParens p) <|> p
+  manyParens $ do
+    name <- atom
+    punct Colon
+    res <- compoundType
+    case res of
+      TType -> return ()
+      Fun args res -> do { newFunction name (FunType args res); return () }
+      Prod [res] -> do { newFunction name (FunType [] res); return () }
+      _ -> fatalError "invalid type"
diff --git a/src/Jukebox/TPTP/ParseSnippet.hs b/src/Jukebox/TPTP/ParseSnippet.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/TPTP/ParseSnippet.hs
@@ -0,0 +1,49 @@
+-- Parse little bits of TPTP, e.g. a prelude for a particular tool.
+
+module Jukebox.TPTP.ParseSnippet where
+
+import Jukebox.TPTP.Parse.Core as TPTP.Parse.Core
+import Jukebox.TPTP.Parsec as TPTP.Parsec
+import Jukebox.TPTP.Lexer
+import Jukebox.Name
+import Jukebox.Form
+import qualified Data.Map.Strict as Map
+import Data.List
+
+tff, cnf :: [(String, Type)] -> [(String, Function)] -> String -> Form
+tff = form TPTP.Parse.Core.tff
+cnf = form TPTP.Parse.Core.cnf
+
+form :: Symbolic a => Parser a -> [(String, Type)] -> [(String, Function)] -> String -> a
+form parser types funs0 str =
+  case run_ (parser <* eof)
+            (UserState (MkState [] (Map.delete "$i" (Map.fromList types)) (Map.fromList funs) Map.empty 0) (scan str)) of
+    Ok (UserState (MkState _ types' funs' _ _) (At _ (Cons Eof _))) res
+      | Map.insert "$i" individual (Map.fromList types) /=
+        Map.insert "$i" individual types' ->
+        error $ "ParseSnippet: type implicitly defined: " ++
+                show (map snd (Map.toList types' \\ types))
+      | Map.fromList funs /= funs' ->
+        error $ "ParseSnippet: function implicitly defined: " ++
+                show (map snd (Map.toList funs' \\ funs))
+      | otherwise -> mapType elimI res
+    Ok{} -> error "ParseSnippet: lexical error"
+    TPTP.Parsec.Error _ msg -> error $ "ParseSnippet: arse error: " ++ msg
+    Expected _ exp -> error $ "ParseSnippet: parse error: expected " ++ show exp
+
+  where
+    funs = map (mapFunType introI) funs0
+
+    mapFunType f (xs, name ::: FunType args res) =
+      (xs, name ::: FunType (map f args) (f res))
+
+    elimI =
+      case lookup "$i" types of
+        Nothing -> id
+        Just i ->
+          \ty -> if ty == individual then i else ty
+    introI =
+      case lookup "$i" types of
+        Nothing -> id
+        Just i ->
+          \ty -> if ty == i then individual else ty
diff --git a/src/Jukebox/TPTP/Parsec.hs b/src/Jukebox/TPTP/Parsec.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/TPTP/Parsec.hs
@@ -0,0 +1,175 @@
+{-# LANGUAGE RankNTypes, BangPatterns, MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, UndecidableInstances, TypeFamilies #-}
+{-# OPTIONS_GHC -funfolding-creation-threshold=10000 -funfolding-use-threshold=10000 #-}
+module Jukebox.TPTP.Parsec where
+
+import Control.Applicative
+import Control.Monad
+import Data.List
+
+-- Parser type and monad instances
+
+newtype Parsec a b = Parsec
+  { runParsec :: forall c.
+                 (b -> Reply a c -> a -> Reply a c) -- ok: success
+              -> Reply a c -- err: backtracking failure
+              -> a -> Reply a c }
+
+type Reply a b = [String] -> Result (Position a) b
+
+data Result a b = Ok a b | Error a String | Expected a [String]
+
+{-# INLINE parseError #-}
+parseError :: [String] -> Parsec a b
+parseError e = Parsec (\_ok err _inp exp -> err (e ++ exp))
+
+{-# INLINE fatalError #-}
+fatalError :: Stream a c => String -> Parsec a b
+fatalError e = Parsec (\_ok _err inp _ -> Error (position inp) e)
+
+instance Functor (Parsec a) where
+  {-# INLINE fmap #-}
+  fmap f x = x >>= return . f
+
+instance Monad (Parsec a) where
+  {-# INLINE return #-}
+  return x = Parsec (\ok err inp exp -> ok x err inp exp)
+  {-# INLINE (>>=) #-}
+  x >>= f = Parsec (\ok err inp exp  -> runParsec x (\y err inp exp -> runParsec (f y) ok err inp exp) err inp exp)
+  {-# INLINE fail #-}
+  fail _ = parseError []
+
+instance MonadPlus (Parsec a) where
+  {-# INLINE mzero #-}
+  mzero = Parsec (\_ok err _inp exp -> err exp)
+  {-# INLINE mplus #-}
+  m1 `mplus` m2 = Parsec (\ok err inp exp ->
+    runParsec m1 ok (\exp -> runParsec m2 ok err inp exp) inp exp)
+
+instance Applicative (Parsec a) where
+  {-# INLINE pure #-}
+  pure = return
+  {-# INLINE (<*>) #-}
+  f <*> x = do { f' <- f; x' <- x; return (f' x') }
+  {-# INLINE (*>) #-}
+  (*>) = (>>)
+  {-# INLINE (<*) #-}
+  x <* y = do
+    x' <- x
+    y
+    return x'
+
+instance Alternative (Parsec a) where
+  {-# INLINE empty #-}
+  empty = mzero
+  {-# INLINE (<|>) #-}
+  (<|>) = mplus
+  {-# INLINE some #-}
+  some p = do { x <- nonempty p; xs <- many p; return (x:xs) }
+  {-# INLINE many #-}
+  many p = p' where p' = liftM2 (:) (nonempty p) p' <|> return []
+  -- Stack overflow-avoiding version:
+  -- many p = liftM reverse (p' [])
+  --   where p' !xs = do { x <- nonempty p; p' (x:xs) } `mplus` return xs
+
+-- Basic combinators
+
+{-# INLINE nonempty #-}
+nonempty :: Parsec a b -> Parsec a b
+nonempty p = p
+
+{-# INLINE skipSome #-}
+skipSome :: Parsec a b -> Parsec a ()
+skipSome p = p' where p' = nonempty p >> (p' `mplus` return ())
+
+{-# INLINE skipMany #-}
+skipMany :: Parsec a b -> Parsec a ()
+skipMany p = p' where p' = (nonempty p >> p') `mplus` return ()
+
+{-# INLINE (<?>) #-}
+infix 0 <?>
+(<?>) :: Parsec a b -> String -> Parsec a b
+p <?> text = Parsec (\ok err inp exp ->
+  runParsec p ok err inp (text:exp))
+
+{-# INLINE between #-}
+between :: Parsec a b -> Parsec a c -> Parsec a d -> Parsec a d
+between p q r = p *> r <* q
+
+{-# INLINE sepBy1 #-}
+sepBy1 :: Parsec a b -> Parsec a c -> Parsec a [b]
+sepBy1 it sep = liftM2 (:) it (many (sep >> it))
+
+-- Running the parser
+
+run_ :: Stream a c => Parsec a b -> a -> Result (Position a) b
+run_ p x = runParsec p ok err x []
+  where ok x _ inp _ = Ok (position inp) x
+        err exp = Expected (position x) (reverse exp)
+
+run :: Stream a c => (Position a -> [String]) -> Parsec a b -> a -> (Position a, Either [String] b)
+run report p ts =
+  case run_ p ts of
+    Ok ts' x -> (ts', Right x)
+    Error ts' e -> (ts', Left [e])
+    Expected ts' e -> (ts', Left (expected (report ts') e))
+
+-- Reporting errors
+
+expected :: [String] -> [String] -> [String]
+expected unexpected [] = unexpected ++ ["Unknown error"]
+expected unexpected expected =
+  unexpected ++ [ "Expected " ++ list expected ]
+  where list [exp] = exp
+        list exp = intercalate ", " (init exp) ++ " or " ++ last exp
+
+-- Token streams
+
+class Stream a b | a -> b where
+  primToken :: a -> (a -> b -> c) -> c -> (String -> c) -> c
+  type Position a
+  position :: a -> Position a
+
+{-# INLINE next #-}
+next :: Stream a b => Parsec a b
+next = Parsec (\ok err inp exp ->
+  primToken inp (\inp' x -> ok x err inp' exp) (err exp) (Error (position inp)))
+
+{-# INLINE cut #-}
+cut :: Stream a b => Parsec a ()
+cut = Parsec (\ok _err inp _exp -> ok () (Expected (position inp)) inp [])
+
+{-# INLINE cut' #-}
+cut' :: Stream a b => Parsec a c -> Parsec a c
+cut' p = Parsec (\ok err inp exp -> runParsec p (\x _ inp' _ -> ok x err inp' []) err inp exp)
+
+{-# INLINE satisfy #-}
+satisfy :: Stream a b => (b -> Bool) -> Parsec a b
+satisfy p = do
+  t <- next
+  guard (p t)
+  cut
+  return t
+
+{-# INLINE eof #-}
+eof :: Stream a b => Parsec a ()
+eof = Parsec (\ok err inp exp ->
+  primToken inp (\_ _ -> err ("end of file":exp)) (ok () err inp exp) (Error (position inp)))
+
+-- User state
+
+data UserState state stream = UserState { userState :: !state, userStream :: !stream }
+
+instance Stream a b => Stream (UserState state a) b where
+  {-# INLINE primToken #-}
+  primToken (UserState state stream) ok err =
+    primToken stream (ok . UserState state) err
+  type Position (UserState state a) = UserState state a
+  position = id
+
+{-# INLINE getState #-}
+getState :: Parsec (UserState state a) state
+getState = Parsec (\ok err inp@UserState{userState = state} exp -> ok state err inp exp)
+
+{-# INLINE putState #-}
+putState :: state -> Parsec (UserState state a) ()
+putState state = Parsec (\ok err UserState{userStream = stream} exp -> ok () err (UserState state stream) exp)
diff --git a/src/Jukebox/TPTP/Print.hs b/src/Jukebox/TPTP/Print.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/TPTP/Print.hs
@@ -0,0 +1,244 @@
+-- Pretty-printing of formulae. WARNING: icky code inside!
+{-# LANGUAGE FlexibleContexts, TypeSynonymInstances, TypeOperators, FlexibleInstances, CPP, GADTs #-}
+module Jukebox.TPTP.Print(prettyShow, showClauses, pPrintClauses, showProblem, pPrintProblem)
+       where
+
+#include "errors.h"
+import Data.Char
+import Text.PrettyPrint.HughesPJ
+import qualified Jukebox.TPTP.Lexer as L
+import Jukebox.Form
+import qualified Data.Map.Strict as Map
+import Data.Map(Map)
+import qualified Data.Set as Set
+import Data.Set(Set)
+import Jukebox.Name
+import Jukebox.Utils
+import Text.PrettyPrint.HughesPJClass
+import Data.Symbol
+
+pPrintClauses :: Problem Clause -> Doc
+pPrintClauses prob0
+  | isFof prob = vcat (map (pPrintInput "cnf" pPrint) prob)
+  | otherwise  = pPrintProblem (map (fmap toForm) prob0)
+  where
+    prob = prettyNames prob0
+
+showClauses :: Problem Clause -> String
+showClauses = show . pPrintClauses
+
+pPrintProblem :: Problem Form -> Doc
+pPrintProblem prob0
+  | isReallyFof prob = vcat (map (pPrintInput "fof" (pPrintFof 0)) prob)
+  | otherwise = vcat (pPrintDecls prob ++ map (pPrintInput "tff" (pPrintTff 0)) prob)
+  where
+    prob = prettyNames prob0
+
+showProblem :: Problem Form -> String
+showProblem = show . pPrintProblem
+
+isReallyFof :: Symbolic a => a -> Bool
+isReallyFof = all p . types
+  where
+    p O = True
+    p (Type ty _ _) | ty == i = True
+    p _ = False
+    i = name "$i"
+
+pPrintDecls :: Problem Form -> [Doc]
+pPrintDecls prob =
+  map typeDecl (usort (types prob)) ++
+  map funcDecl (usort (functions prob))
+  where
+    typeDecl O = empty
+    typeDecl (Type ty _ _) | ty == i = empty
+    typeDecl ty = typeClause ty (text "$tType")
+    i = name "$i"
+
+    funcDecl (f ::: ty) = typeClause f (pPrint ty)
+    typeClause name ty =
+      pPrintClause "tff" "type" "type"
+        (pPrint name <> colon <+> ty)
+
+instance Pretty a => Pretty (Input a) where
+  pPrint = pPrintInput "tff" pPrint
+instance Pretty a => Show (Input a) where
+  show = prettyShow
+
+pPrintInput :: String -> (a -> Doc) -> Input a -> Doc
+pPrintInput family pp i =
+  pPrintClause family (tag i) (show (kind i)) (pp (what i))
+
+pPrintClause :: String -> String -> String -> Doc -> Doc
+pPrintClause family name kind rest =
+  text family <> parens (sep [text name <> comma <+> text kind <> comma, rest]) <> text "."
+
+instance Pretty Clause where
+  pPrint (Clause (Bind _ ts)) =
+    pPrintConnective undefined 0 "$false" "|" (map Literal ts)
+
+instance Show Clause where
+  show = prettyShow
+
+instance Pretty Type where
+  pPrint O = text "$o"
+  pPrint ty = text . escapeAtom . show . tname $ ty
+
+instance Show Type where
+  show = prettyShow
+
+instance Pretty FunType where
+  pPrint FunType{args = args, res = res} =
+    case args of
+      [] -> pPrint res
+      args -> pPrintTypes args <+> text ">" <+>
+              pPrint res
+    where
+      pPrintTypes [arg] = pPrint arg
+      pPrintTypes args =
+        parens . hsep . punctuate (text " *") . map pPrint $ args
+
+instance Show FunType where
+  show = prettyShow
+
+instance Pretty Name where
+  pPrint = text . show
+
+instance Show L.Token where
+  show L.Atom{L.tokenName = x} = escapeAtom x
+  show L.Defined{L.defined = x} = show x
+  show L.Var{L.tokenName = x} = x
+  show L.DistinctObject{L.tokenName = x} = quote '"' x
+  show L.Number{L.value = x} = show x
+  show L.Punct{L.kind = x} = show x
+  show L.Eof = "end of file"
+  show L.Error = "lexical error"
+
+escapeAtom :: String -> String
+escapeAtom s | not (null s') && isLower (head s') && all isNormal s' = s
+             | otherwise = quote '\'' s
+  where isNormal c = isAlphaNum c || c == '_'
+        s' = dropWhile (== '$') s
+
+quote :: Char -> String -> String
+quote c s = [c] ++ concatMap escape s ++ [c]
+  where escape c' | c == c' = ['\\', c]
+        escape '\\' = "\\\\"
+        escape c = [c]
+
+instance Pretty Term where
+  pPrint (Var (v ::: _)) =
+    pPrint v
+  pPrint ((f ::: _) :@: []) =
+    text (escapeAtom (show f))
+  pPrint ((f ::: _) :@: ts) =
+    text (escapeAtom (show f)) <>
+    parens (sep (punctuate comma (map pPrint ts)))
+
+instance Show Term where
+  show = prettyShow
+
+instance Pretty Atomic where
+  pPrint (t :=: u) = pPrint t <> text "=" <> pPrint u
+  pPrint (Tru t) = pPrint t
+
+instance Show Atomic where
+  show = prettyShow
+
+instance Pretty Form where
+  pPrintPrec _ = pPrintTff
+
+instance Show Form where
+  show = prettyShow
+
+pPrintFof, pPrintTff :: Rational -> Form -> Doc
+pPrintFof = pPrintForm (\(x ::: _) -> pPrint x)
+pPrintTff = pPrintForm (\(x ::: ty) -> pPrint x <> colon <+> pPrint ty)
+
+pPrintForm :: (Variable -> Doc) -> Rational -> Form -> Doc
+-- We use two precedences, the lowest for binary connectives
+-- and the highest for everything else.
+pPrintForm _bind _p (Literal (Pos (t :=: u))) =
+  pPrint t <> text "=" <> pPrint u
+pPrintForm _bind _p (Literal (Neg (t :=: u))) =
+  pPrint t <> text "!=" <> pPrint u
+pPrintForm _bind p (Literal (Pos t)) = pPrintPrec prettyNormal p t
+pPrintForm bind p (Literal (Neg t)) = pPrintForm bind p (Not (Literal (Pos t)))
+pPrintForm bind _p (Not f) = text "~" <> pPrintForm bind 1 f
+pPrintForm bind p (And ts) = pPrintConnective bind p "$true" "&" ts
+pPrintForm bind p (Or ts) = pPrintConnective bind p "$false" "|" ts
+pPrintForm bind p (Equiv t u) = pPrintConnective bind p undefined "<=>" [t, u]
+pPrintForm bind _p (ForAll (Bind vs f)) = pPrintQuant bind "!" vs f
+pPrintForm bind _p (Exists (Bind vs f)) = pPrintQuant bind "?" vs f
+pPrintForm bind p (Connective c t u) = pPrintConnective bind p (error "pPrint: Connective") (show c) [t, u]
+
+instance Show Connective where
+  show Implies = "=>"
+  show Follows = "<="
+  show Xor = "<~>"
+  show Nor = "~|"
+  show Nand = "~&"
+
+pPrintConnective _bind _p ident _op [] = text ident
+pPrintConnective bind p _ident _op [x] = pPrintForm bind p x
+pPrintConnective bind p _ident op (x:xs) =
+  maybeParens (p > 0) $
+    sep (ppr x:[ nest 2 (text op <+> ppr x) | x <- xs ])
+      where ppr = pPrintForm bind 1
+            
+pPrintQuant :: (Variable -> Doc) -> String -> Set.Set Variable -> Form -> Doc
+pPrintQuant bind q vs f
+  | Set.null vs = pPrintForm bind 1 f
+  | otherwise =
+    sep [
+      text q <> brackets (sep (punctuate comma (map bind (Set.toList vs)))) <> colon,
+      nest 2 (pPrintForm bind 1 f)]
+
+instance Show Kind where
+  show Axiom = "axiom"
+  show Conjecture = "conjecture"
+  show Question = "question"
+
+prettyNames :: Symbolic a => a -> a
+prettyNames x0 = mapName replace x
+  where
+    replace name@Fixed{}  = name
+    replace name@Unique{} = Map.findWithDefault __ name sub
+
+    sub = globalsScope `Map.union` pretty globalsUsed x
+
+    pretty :: Symbolic a => Set String -> a -> Map Name Name
+    pretty used x =
+      case typeOf x of
+        Bind_ -> bind used x
+        _ -> collect (pretty used) x
+
+    bind :: Symbolic a => Set String -> Bind a -> Map Name Name
+    bind used (Bind vs x) =
+      scope `Map.union` pretty used' x
+      where
+        (scope, used') = add used (map name (Set.toList vs))
+
+    add used names =
+      foldr add1 (Map.empty, used) names
+
+    add1 (Fixed xs) (scope, used) =
+      (scope, Set.insert (unintern xs) used)
+    add1 name@(Unique _ base f) (scope, used) =
+      (Map.insert name (Fixed (intern winner)) scope,
+       Set.insert winner (Set.fromList taken `Set.union` used))
+      where
+        cands = [f base n | n <- [0..]]
+        Renaming taken winner =
+          head [c | c@(Renaming xs x) <- cands,
+                not (or [Set.member y used | y <- x:xs ])]
+
+    globals =
+      usort $
+        [ f | f ::: _ <- functions x ] ++
+        [ ty | Type ty _ _ <- types x ]
+    (globalsScope, globalsUsed) = add fixed globals
+
+    fixed = Set.fromList [ unintern xs | Fixed xs <- names x ]
+
+    x = run x0 uniqueNames
diff --git a/src/Jukebox/Toolbox.hs b/src/Jukebox/Toolbox.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/Toolbox.hs
@@ -0,0 +1,202 @@
+{-# LANGUAGE RecordWildCards #-}
+module Jukebox.Toolbox where
+
+import Jukebox.Options
+import Jukebox.Form
+import Jukebox.Name
+import Jukebox.TPTP.Print
+import Control.Monad
+import Jukebox.Clausify hiding (run)
+import Jukebox.TPTP.Parse
+import Jukebox.Monotonox.Monotonicity hiding (guards)
+import Jukebox.Monotonox.ToFOF
+import System.Exit
+import System.IO
+import Jukebox.TPTP.FindFile
+import Jukebox.GuessModel
+import Jukebox.InferTypes
+import qualified Data.Map.Strict as Map
+
+data GlobalFlags =
+  GlobalFlags {
+    quiet :: Bool }
+  deriving Show
+
+globalFlags :: OptionParser GlobalFlags
+globalFlags =
+  inGroup "Global options" $
+  GlobalFlags <$>
+    bool "quiet"
+      ["Do not print any informational output.",
+       "Default: (off)"]
+
+(=>>=) :: (Monad m, Applicative f) => f (a -> m b) -> f (b -> m c) -> f (a -> m c)
+f =>>= g = (>=>) <$> f <*> g
+infixl 1 =>>= -- same as >=>
+
+(=>>) :: (Monad m, Applicative f) => f (m a) -> f (m b) -> f (m b)
+x =>> y = (>>) <$> x <*> y
+infixl 1 =>> -- same as >>
+
+greetingBox :: Tool -> OptionParser (IO ())
+greetingBox t = greetingBoxIO t <$> globalFlags
+
+greetingBoxIO :: Tool -> GlobalFlags -> IO ()
+greetingBoxIO t GlobalFlags{quiet = quiet} =
+  unless quiet $ hPutStrLn stderr (greeting t)
+
+allFilesBox :: OptionParser ((FilePath -> IO ()) -> IO ())
+allFilesBox = flip allFiles <$> filenames
+
+allFiles :: (FilePath -> IO ()) -> [FilePath] -> IO ()
+allFiles _ [] = do
+  hPutStrLn stderr "No input files specified! Try --help."
+  exitWith (ExitFailure 1)
+allFiles f xs = mapM_ f xs
+
+parseProblemBox :: OptionParser (FilePath -> IO (Problem Form))
+parseProblemBox = parseProblemIO <$> findFileFlags
+
+parseProblemIO :: [FilePath] -> FilePath -> IO (Problem Form)
+parseProblemIO dirs f = do
+  r <- parseProblem dirs f
+  case r of
+    Left err -> do
+      hPutStrLn stderr err
+      exitWith (ExitFailure 1)
+    Right x -> return x
+
+clausifyBox :: OptionParser (Problem Form -> IO CNF)
+clausifyBox = clausifyIO <$> globalFlags <*> clausifyFlags
+
+clausifyIO :: GlobalFlags -> ClausifyFlags -> Problem Form -> IO CNF
+clausifyIO globals flags prob = do
+  unless (quiet globals) $ hPutStrLn stderr "Clausifying problem..."
+  return $! clausify flags prob
+
+toFofBox :: OptionParser (Problem Form -> IO (Problem Form))
+toFofBox = toFofIO <$> globalFlags <*> clausifyBox <*> schemeBox
+
+oneConjectureBox :: OptionParser (CNF -> IO (Problem Clause))
+oneConjectureBox = pure oneConjecture
+
+oneConjecture :: CNF -> IO (Problem Clause)
+oneConjecture cnf = run cnf f
+  where f (CNF cs [cs'] _ _) = return (return (cs ++ cs'))
+        f _ = return $ do
+          hPutStrLn stderr "Error: more than one conjecture found in input problem"
+          exitWith (ExitFailure 1)
+
+toFofIO :: GlobalFlags -> (Problem Form -> IO CNF) -> Scheme -> Problem Form -> IO (Problem Form)
+toFofIO globals clausify scheme f = do
+  cs <- clausify f >>= oneConjecture
+  unless (quiet globals) $ hPutStrLn stderr "Monotonicity analysis..."
+  m <- monotone (map what cs)
+  let isMonotone ty =
+        case Map.lookup ty m of
+          Just Nothing -> False
+          Just (Just _) -> True
+          Nothing  -> True -- can happen if clausifier removed all clauses about a type
+  return (translate scheme isMonotone f)
+
+schemeBox :: OptionParser Scheme
+schemeBox =
+  choose <$>
+  flag "encoding"
+    ["Which type encoding to use.",
+     "Default: --encoding guards"]
+    "guards"
+    (argOption ["guards", "tags"])
+  <*> tagsFlags
+  where choose "guards" _flags = guards
+        choose "tags" flags = tags flags
+
+monotonicityBox :: OptionParser (Problem Clause -> IO String)
+monotonicityBox = monotonicity <$> globalFlags
+
+monotonicity :: GlobalFlags -> Problem Clause -> IO String
+monotonicity globals cs = do
+  unless (quiet globals) $ hPutStrLn stderr "Monotonicity analysis..."
+  m <- monotone (map what cs)
+  let info (ty, Nothing) = [base ty ++ ": not monotone"]
+      info (ty, Just m) =
+        [prettyShow ty ++ ": monotone"] ++
+        concat
+        [ case ext of
+             CopyExtend -> []
+             TrueExtend -> ["  " ++ base p ++ " true-extended"]
+             FalseExtend -> ["  " ++ base p ++ " false-extended"]
+        | (p, ext) <- Map.toList m ]
+
+  return (unlines (concat (map info (Map.toList m))))
+
+annotateMonotonicityBox :: OptionParser (Problem Clause -> IO (Problem Clause))
+annotateMonotonicityBox = (\globals x -> do
+  unless (quiet globals) $ putStrLn "Monotonicity analysis..."
+  annotateMonotonicity x) <$> globalFlags
+
+prettyPrintProblemBox :: OptionParser (Problem Form -> IO ())
+prettyPrintProblemBox = prettyPrintIO showProblem <$> globalFlags <*> writeFileBox
+
+prettyPrintClausesBox :: OptionParser (Problem Clause -> IO ())
+prettyPrintClausesBox = prettyPrintIO showClauses <$> globalFlags <*> writeFileBox
+
+prettyPrintIO :: (a -> String) -> GlobalFlags -> (String -> IO ()) -> a -> IO ()
+prettyPrintIO shw globals write prob = do
+  unless (quiet globals) $ hPutStrLn stderr "Writing output..."
+  write (shw prob ++ "\n")
+
+writeFileBox :: OptionParser (String -> IO ())
+writeFileBox =
+  flag "output"
+    ["Where to write the output.",
+     "Default: stdout"]
+    putStr
+    (fmap myWriteFile argFile)
+  where myWriteFile "/dev/null" _ = return ()
+        myWriteFile file contents = writeFile file contents
+
+guessModelBox :: OptionParser (Problem Form -> IO (Problem Form))
+guessModelBox = guessModelIO <$> expansive <*> universe
+  where universe = choose <$>
+                   flag "universe"
+                   ["Which universe to find the model in.",
+                    "Default: peano"]
+                   "peano"
+                   (argOption ["peano", "trees"])
+        choose "peano" = Peano
+        choose "trees" = Trees
+        expansive = manyFlags "expansive"
+                    ["Allow a function to construct 'new' terms in its base base."]
+                    (arg "<function>" "expected a function name" Just)
+
+guessModelIO :: [String] -> Universe -> Problem Form -> IO (Problem Form)
+guessModelIO expansive univ prob = return (guessModel expansive univ prob)
+
+allObligsBox :: OptionParser ((Problem Clause -> IO Answer) -> CNF -> IO ())
+allObligsBox = pure allObligsIO
+
+allObligsIO solve CNF{..} = loop 1 conjectures
+  where loop _ [] = result unsatisfiable
+        loop i (c:cs) = do
+          when multi $ putStrLn $ "Part " ++ part i
+          answer <- solve (axioms ++ c)
+          when multi $ putStrLn $ "+++ PARTIAL (" ++ part i ++ "): " ++ show answer
+          case answer of
+            Satisfiable -> result satisfiable
+            Unsatisfiable -> loop (i+1) cs
+            NoAnswer x -> result (show x)
+        multi = length conjectures > 1
+        part i = show i ++ "/" ++ show (length conjectures)
+        result x = putStrLn ("+++ RESULT: " ++ x)
+
+inferBox :: OptionParser (Problem Clause -> IO (Problem Clause, Type -> Type))
+inferBox = (\globals prob -> do
+  unless (quiet globals) $ putStrLn "Inferring types..."
+  return (run prob inferTypes)) <$> globalFlags
+
+printInferredBox :: OptionParser ((Problem Clause, Type -> Type) -> IO (Problem Clause))
+printInferredBox = pure $ \(prob, rep) -> do
+  forM_ (types prob) $ \ty ->
+    putStrLn $ show ty ++ " => " ++ show (rep ty)
+  return prob
diff --git a/src/Jukebox/UnionFind.hs b/src/Jukebox/UnionFind.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/UnionFind.hs
@@ -0,0 +1,76 @@
+module Jukebox.UnionFind(UF, Replacement((:>)), (=:=), rep, evalUF, execUF, runUF, S, isRep, initial, reps) where
+
+import Prelude hiding (min)
+import Control.Monad
+import Control.Monad.Trans.State.Strict
+import Data.Map.Strict(Map)
+import qualified Data.Map as Map
+
+type S a = Map a a
+type UF a = State (S a)
+data Replacement a = a :> a
+
+runUF :: S a -> UF a b -> (b, S a)
+runUF s m = runState m s
+
+evalUF :: S a -> UF a b -> b
+evalUF s m = fst (runUF s m)
+
+execUF :: S a -> UF a b -> S a
+execUF s m = snd (runUF s m)
+
+initial :: S a
+initial = Map.empty
+
+(=:=) :: Ord a => a -> a -> UF a (Maybe (Replacement a))
+s =:= t | s == t = return Nothing
+s =:= t = do
+  rs <- rep s
+  rt <- rep t
+  case rs `compare` rt of
+    EQ -> return Nothing
+    LT -> do
+      modify (Map.insert rt rs)
+      return (Just (rt :> rs))
+    GT -> do
+      modify (Map.insert rs rt)
+      return (Just (rs :> rt))
+
+{-# INLINE rep #-}
+rep :: Ord a => a -> UF a a
+rep s = do
+  m <- get
+  case Map.lookup s m of
+    Nothing -> return s
+    Just t -> do
+      u <- rep t
+      when (t /= u) $ modify (Map.insert s u)
+      return u
+      -- case Map.lookup t m of
+      --   Nothing -> return t
+      --   Just u -> do
+      --     v <- rep' t u
+      --     modify (Map.insert s v)
+      --     return v
+
+reps :: Ord a => UF a (a -> a)
+reps = do
+  s <- get
+  return (\x -> evalUF s (rep x))
+
+-- rep' :: Ord a => a -> a -> UF a a
+-- rep' s t = do
+--   m <- get
+--   case Map.lookup t m of
+--     Nothing -> do
+--       modify (Map.insert s t)
+--       return t
+--     Just u -> do
+--       v <- rep' t u
+--       modify (Map.insert s v)
+--       return v
+
+isRep :: Ord a => a -> UF a Bool
+isRep t = do
+  t' <- rep t
+  return (t == t')
diff --git a/src/Jukebox/Utils.hs b/src/Jukebox/Utils.hs
new file mode 100644
--- /dev/null
+++ b/src/Jukebox/Utils.hs
@@ -0,0 +1,31 @@
+{-# LANGUAGE TupleSections #-}
+module Jukebox.Utils where
+
+import System.Process
+import System.IO
+import System.Exit
+import Control.Concurrent
+import qualified Data.Set as Set
+
+usort :: Ord a => [a] -> [a]
+--usort = map head . group . sort
+usort = Set.toAscList . Set.fromList
+
+merge :: Ord a => [a] -> [a] -> [a]
+merge [] ys = ys
+merge xs [] = xs
+merge (x:xs) (y:ys) =
+  case x `compare` y of
+    LT -> x:merge xs (y:ys)
+    EQ -> x:merge xs ys
+    GT -> y:merge (x:xs) ys
+
+popen :: FilePath -> [String] -> String -> IO (ExitCode, String)
+popen prog args inp = do
+  (stdin, stdout, stderr_, pid) <- runInteractiveProcess prog args Nothing Nothing
+  forkIO $ hGetContents stderr_ >>= hPutStr stderr
+  hPutStr stdin inp
+  hFlush stdin
+  hClose stdin
+  code <- waitForProcess pid
+  fmap (code,) (hGetContents stdout) <* hClose stdout
