diff --git a/Hascal.hs b/Hascal.hs
--- a/Hascal.hs
+++ b/Hascal.hs
@@ -1,175 +1,182 @@
--- |Hascal is both a simple but extendable calculator library for Haskell
--- and a command-line program using it.
--- 
--- Also, its source code is a nice example for a minimalistic Haskell project.
--- 
--- Some examples for the usage of the command-line program (using bash):
--- 
--- >>> hascal 1+2
--- 3.0
--- 
--- >>> hascal 1+2*3-4/198^2
--- 6.99989796959493929190898887868584838281807978777676
--- 
--- Also, preceding exclamation marks mean that the following number is
--- imaginary, that is, you have to multiply it with i. E.g.:
--- 
--- >>> hascal _1 ^ 0.5
--- !1.0
--- 
--- And as you can see, negative numbers are preceded by an underscore.
--- 
--- Although hascal itself doesn't understand brackets, you can use your shell
--- to get that functionality, like this (using bash):
--- 
--- >>> hascal e ^ $(hascal i*pi)
--- -1.0
--- 
--- Speaking of shells, you should consider that your shell might extend an
--- asterisk (*) to the files at the current directory, like this:
--- 
--- >>> echo *
--- _darcs dist hascal.cabal Hascal.hs LICENSE Main.hs README.org Setup.hs
--- 
--- That's why this might not work:
--- 
--- >>> hascal 1 * 2
--- Error. :(
--- 
--- But you could do this instead:
--- 
--- >>> hascal 1*2
--- 2
--- 
--- Or, you could do:
--- 
--- >>> hascal '1*2'
--- 2
+-- |Hascal is a simple, minimalistic, tiny calculator library and program.
+--
+-- * Hascal only understands single-character operators.
+-- * Hascal only understands infix operators.
+-- * Hascal does not understand parantheses.
+-- * @_@ is hard-coded as single prefix for negating numbers.
+-- * By default, Hascal understands the operators @+@, @-@, @*@, @/@, @^@, and
+-- @?@ (logarithm).
+-- * By default, Hascal understands the constants @pi@, @e@, and @i@.
+-- * Using Hascal as a library, you can add new operators and new constants
+-- using a configuration data type.
+--
+-- The hascal executable program is easy to use. In a shell, type:
 -- 
--- Yeah, that's pretty much it. Hascal is really minimalistic.
--- And I'm not planning to extend it much.
-module Hascal (
-  -- * Operators
-  operators,
-  -- * Evaluators
-  eval,
-  hascal,
-  -- * Pretty Printers
-  prettyPrint
+-- >>> hascal 1+2-3*4/5^6?7
+-- -1.7263530417152033
+--
+-- Given a configuration, the 'hascal' function similarly evaluates an
+-- expression of type 'String'. In a Haskell interpreter like GHCI, type:
+--
+-- >>> hascal def "1+2-3*4/5^6?7"
+-- Right (0.2736469582847967 :+ 0.0)
+--
+-- >>> hascal def "1++2"
+-- Left "Error at \"\"."
+
+--------------------------------------------------------------------------------
+
+module Hascal
+  ( Config(..)
+  , Data.Default.Default(..)
+  , hascal
+  , showHascal
+  , showNumber
   ) where
 
 
-import Control.Arrow (second)
-import Data.Complex  (Complex(..))
-import Data.Functor  ((<$>))
-import Data.List     (find)
+--------------------------------------------------------------------------------
 
+import Data.Complex
+import Data.Default
+import Data.List
+import Data.List.Split
 
 
--- |'operators' is the default list of operators.
--- 
--- An operator consists of one character and a function.
--- 
--- 'operators' includes:
--- 
--- * addition, represented by @\'+\'@,
--- 
--- * subtraction, represented by @\'-\'@,
--- 
--- * multiplication, represented by @\'*\'@,
--- 
--- * division, represented by @\'\/\'@,
--- 
--- * exponentiation, represented by @\'^\'@, and
--- 
--- * logarithming (with flipped arguments, see below), represented by @\'?\'@,
--- 
--- such that these laws are held:
--- 
--- > (a - b == c) == (a == b + c)
--- > (a / b == c) == (a == b * c)
--- > (a ? b == c) == (a == b ^ c)
-operators :: RealFloat t
-          => [(Char, Complex t -> Complex t -> Complex t)]
-operators = [ ('+', (+))
-            , ('-', (-))
-            , ('/', (/))
-            , ('*', (*))
-            , ('^', (**))
-            , ('?', flip logBase)
-            ]
+--------------------------------------------------------------------------------
+-- | The result of an evaluation of a string is either a String containing an
+-- error message or a complex number.
 
+type Result   t = Either String (Complex t)
 
+
+--------------------------------------------------------------------------------
+-- | An operator is a pair of
+-- * a 'Char' containing its identifier; and
+-- * a binary numeral function.
+
+type Operator t = (Char, Complex t -> Complex t -> Complex t)
+
+
+--------------------------------------------------------------------------------
+
+-- | A constant is a pair of
+-- * a 'String' containing its identifier; and
+-- * a 'Complex' number containing its value.
+
+type Constant t = (String, Complex t)
+
+
+--------------------------------------------------------------------------------
+
+-- | A configuration. 'def' is the default configuration.
+
+data Config t = Config
+    { operators :: [Operator t] -- ^ A list of operators. The order in this list also determines the order of evaluation.
+    , constants :: [Constant t] -- ^ A list of constants.
+    }
+
+
+instance (Read t, RealFloat t) => Default (Config t) where
+    def = Config
+        [ ('+', (+))
+        , ('-', (-))
+        , ('*', (*))
+        , ('/', (/))
+        , ('^', (**))
+        , ('?', flip logBase)
+        ]
+        [ ("pi", pi   :+0)
+        , ("e" , exp 1:+0)
+        , ("i" , 0    :+1)
+        ]
+
+
+--------------------------------------------------------------------------------
+
+-- | Given a configuration and a 'String'-expression, returns a 'String'
+-- containing the error message or the resulting complex number.
+
+showHascal :: (Show t, Read t, RealFloat t)
+           => Config t
+           -> String
+           -> String
+showHascal conf s = either id showNumber (hascal conf s)
+
+
+--------------------------------------------------------------------------------
+
+-- | Given a configuration and a 'String'-expression, returns 'Either' a
+-- 'String' containing an error message; or a 'Complex' number.
+
+hascal :: (Read t, RealFloat t) => Config t -> String -> Result t
+hascal conf = calc (operators conf) (constants conf)
+
+
+--------------------------------------------------------------------------------
+
+-- Given a list of operators, a list of constants, and a 'String'-expression,
+-- returns 'Either' a 'String' containing an error message; or a 'Complex'
+-- number.
+
 calc :: (Read t, RealFloat t)
-     => [(Char, Complex t -> Complex t -> Complex t)]
+     => [Operator t]
+     -> [Constant t]
      -> String
-     -> Either String (Complex t)
-calc []          a
-    = readNumber a
-calc l@((c,f):s) a
-    | z /= ""
-    = case (calc l y,calc l z) of
-        (Right n,Right m) -> Right (f m n)
-        (Left  n,_      ) -> Left n
-        (_      ,Left  m) -> Left m
-    | otherwise
-    = calc s a
+     -> Result t
+calc []             cs s = readNumber cs s
+calc ((c, f) : ops) cs s =
+    foldl1 apply (map (calc ops cs) (splitOn [c] s))
   where
-    (y,z) = second (drop 1) $ break (==c) a
+    apply x y = case (x, y) of
+        (Right rx, Right ry) -> Right (f rx ry)
+        (Left  rx, _       ) -> Left rx
+        (_       , Left  ry) -> Left ry
 
 
--- |'eval' gets a list of operators and a string containing a mathematical
--- expression/term which only uses those operators listed in the first
--- argument, and returns the result of that term.
-eval :: (Read t, RealFloat t)
-     => [(Char, Complex t -> Complex t -> Complex t)] -- ^ list of operators
-     -> String                                        -- ^ string containing term
-     -> Either String (Complex t)                     -- ^ just result, or nothing
-eval = (. reverse) . calc
+--------------------------------------------------------------------------------
 
+-- 'Either' returns a 'String' containing an error message or returns a
+-- complex number represented in the given 'String' as a 'Constant' or as a
+-- number. It’s a wrapper around 'findOrRead', adding the underscore prefix
+-- operator for negation.
 
--- Respects preceding exclamation marks and underscores before a number
-readNumber :: (Read t, RealFloat t) => String -> Either String (Complex t)
-readNumber x = case reverse x of
-                 ('!':s) -> ((0:+1)*) <$> findOrRead s
-                 ('_':s) ->    negate <$> findOrRead s
-                 ('-':s) -> Left ("Error at \"-" ++
-                                  s ++
-                                  "\".\n\nTo denote negative numbers, " ++
-                                  "use a preceding underscore instead.")
-                 s       ->               findOrRead s
+readNumber :: (Read t, RealFloat t)
+           => [Constant t]
+           -> String
+           -> Result t
+readNumber cs ('_':s) = fmap negate (findOrRead cs s)
+readNumber cs      s  = findOrRead cs s
 
 
--- Checks whether the string is readable as a mathematical constant before
--- trying to read it as a number
-findOrRead :: (Read t, Floating t) => String -> Either String (Complex t)
-findOrRead s = maybe (maybeRead s) (Right . snd) $ find ((==s) . fst)
-               [("pi",pi   :+0)
-               ,("e" ,exp 1:+0)
-               ,("i" ,0    :+1)
-               ]
+--------------------------------------------------------------------------------
 
+-- 'Either' returns a 'String' containing an error message or returns a
+-- complex number represented in the given 'String' as a 'Constant' or as a
+-- number.
 
--- Reads numbers
-maybeRead :: (Read t, Num t) => String -> Either String (Complex t)
-maybeRead s
-    | any (null . snd) (reads s :: [(Double,String)])
-    = Right (read s:+0)
-    | otherwise
-    = Left ("Error at \"" ++ s ++ "\".")
+findOrRead :: (Read t, Floating t)
+           => [Constant t]
+           -> String
+           -> Result t
+findOrRead cs s = maybe (maybeRead s) (Right . snd) (find ((==s) . fst) cs)
+  where
+    maybeRead s
+      | any (null . snd) (reads s :: [(Double,String)]) -- TODO: solve this better
+      = Right (read s:+0)
+      | otherwise
+      = Left ("Error at \"" ++ s ++ "\".")
 
 
--- |'hascal' is the default evaluator:
--- 
--- @ hascal = 'eval' 'operators' @
-hascal :: (Read t, RealFloat t) => String -> Either String (Complex t)
-hascal = eval operators
+--------------------------------------------------------------------------------
 
+-- | Show a 'Complex' number a little bit more human-readable by matching both
+-- the real and the imaginery part against zero and one.
 
--- |'prettyPrint' prints a number nicely.
--- E.g., it doesn't show the real or imaginary part of the number if it's @0@.
-prettyPrint :: (Show t, RealFloat t) => Complex t -> String
-prettyPrint (r:+0) = show r
-prettyPrint (r:+1) = prettyPrint (r:+0) ++ " + i"
-prettyPrint (0:+i) = show i ++ "*i"
-prettyPrint (r:+i) = show r ++ " + " ++ show i ++ "*i"
+showNumber :: (Show t, RealFloat t)
+           => Complex t
+           -> String
+showNumber (r:+0) = show r
+showNumber (r:+1) = show r ++ " + i"
+showNumber (0:+i) = show i ++ " * i"
+showNumber (r:+i) = show r ++ " + " ++ show i ++ " * i"
diff --git a/Main.hs b/Main.hs
--- a/Main.hs
+++ b/Main.hs
@@ -2,17 +2,12 @@
 
 import Control.Monad
 import System.Environment
-import Data.Number.CReal
-import Data.Complex
-
+--import Data.Number.CReal
+--import Data.Complex
 import Hascal
 
 
 main :: IO ()
 main = do
   args <- getArgs
-  unless (null args) $
-    putStrLn $
-      either id prettyPrint $
-        (hascal :: String -> Either String (Complex CReal)) $
-          concat args
+  unless (null args) $ putStrLn $ showHascal def $ concat args
diff --git a/Test.hs b/Test.hs
deleted file mode 100644
--- a/Test.hs
+++ /dev/null
@@ -1,39 +0,0 @@
-import Prelude               hiding (succ)
-import Test.HUnit            hiding (test)
-import Control.Monad (liftM)
-import Data.Complex
-
-import Hascal
-
-
-
-main :: IO Int
-main = liftM (\x -> errors x + failures x) (runTestTT tests)
-
-
-
-tests :: Test
-tests = TestList
-        [ succ "_5"           ((-5):+0)
-        , succ "2+7"          (9:+0)
-        , succ "3-4"          ((-1):+0)
-        , succ "9*8"          (72:+0)
-        , succ "9/3"          (3:+0)
-        , succ "1+2-3-4+5"    ((1+2-3-4+5):+0)
-        , succ "8/4+_2-96^2"  ((8/4-2-96**2):+0)
-        ]
-
-
-test :: (Read t, RealFloat t, Show t)
-     => String -> Maybe (Complex t) -> Test
-test string value = TestLabel string $ TestCase $
-                    assertEqual string value (hascal string)
-
-
-succ :: (Read t, RealFloat t, Show t)
-     => String -> Complex t -> Test
-succ string value = test string (Just value)
-
-
-flop :: String -> t -> Test
-flop string value = test string Nothing
diff --git a/hascal.cabal b/hascal.cabal
--- a/hascal.cabal
+++ b/hascal.cabal
@@ -1,5 +1,5 @@
 name:          hascal
-version:       2.0.0.1
+version:       3.0
 synopsis:      A minimalistic but extensible and precise calculator
 description:   Hascal is both a simple but extendable calculator library for
                Haskell as well as a command-line program using this library.
@@ -11,38 +11,31 @@
                Hascal also supports complex numbers. Hascal can work at an
                arbitrary precision. However, Hascal does not support
                parenthesis.
-stability:     provisional
+stability:     experimental
 category:      Math, Console, Tools, Utility, Utils, Parsing
-homepage:      http://darcsden.com/mekeor/hascal
-bug-reports:   http://darcsden.com/mekeor/hascal/issues
+homepage:      https://github.com/mekeor/hascal
+bug-reports:   https://github.com/mekeor/hascal/issues
 license:       GPL
 license-file:  LICENSE
-copyright:     2012 Mekeor Melire
-author:        Mekeor Melire <mekeor.melire@googlemail.com>
-maintainer:    Mekeor Melire <mekeor.melire@googlemail.com>
-tested-with:   GHC ==7.4.1
+copyright:     2017 Mekeor Melire
+author:        Mekeor Melire <mekeor.melire@gmail.com>
+maintainer:    Mekeor Melire <mekeor.melire@gmail.com>
 cabal-version: >= 1.8
 build-type:    Simple
-
+  
 
 source-repository head
-  type:     darcs
-  location: http://hub.darcs.net/mekeor/hascal
+  type:     git
+  location: https://github.com/mekeor/hascal
 
 
-test-suite test
-  type:          exitcode-stdio-1.0
-  main-is:       Test.hs
-  build-depends: HUnit ==1.2.*
-  
-
 library
-  build-depends:   base >2 && <5
+  build-depends:   base == 4.* , data-default == 0.7.*, split == 0.2.*
   exposed-modules: Hascal
   ghc-options:     -Wall
 
 
 executable hascal
-  build-depends:   base >2 && <5, numbers >= 3000
+  build-depends:   base == 4.* , data-default == 0.7.*, split == 0.2.*
   main-is:         Main.hs
   ghc-options:     -Wall
