diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,9 +1,16 @@
 HEAD
 ====
 
+0.2.2.0
+=======
+
+- `ReplOpts` configuration type and `evalReplOpts` function.
+- Only use `fail` for GHC<8.0
+
 0.2.1.0
 =======
 
+- Add `exceptions` dependency.
 - Add a `MonadFail` instance to `HaskelineT`.
 
 0.2.0.0
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -8,6 +8,13 @@
 transformers. Mostly exists because I got tired of implementing the same interface for simple shells over and
 over and decided to canonize the giant pile of hacks that I use to make Haskeline work.
 
+Examples
+--------
+
+* [Simple](examples/Simple.hs)
+* [Prefix](examples/Prefix.hs)
+* [Stateful](examples/Stateful.hs)
+
 Usage
 -----
 
@@ -49,8 +56,9 @@
 Trying it out:
 
 ```haskell
-$ runhaskell Simple.hs
-# Or if in a sandbox: cabal exec runhaskell Simple.hs
+$ stack repl Simple.hs
+Prelude> main
+
 Welcome!
 >>> <TAB>
 kirk spock mccoy
@@ -113,7 +121,7 @@
 -- Tab completion inside of StateT
 repl :: IO ()
 repl = flip evalStateT Set.empty
-     $ evalRepl (pure ">>> ") cmd opts Nothing (Word comp) init
+     $ evalRepl (pure ">>> ") cmd opts Nothing (Word comp) ini
 ```
 
 
@@ -170,7 +178,9 @@
 Trying it out:
 
 ```haskell
-$ runhaskell Main.hs
+$ stack repl examples/Prefix.hs
+Prelude> main
+
 >>> :file <TAB>
 sample1.txt sample2.txt
 
@@ -183,5 +193,5 @@
 License
 -------
 
-Copyright (c) 2014-2019, Stephen Diehl
+Copyright (c) 2014-2020, Stephen Diehl
 Released under the MIT License
diff --git a/repline.cabal b/repline.cabal
--- a/repline.cabal
+++ b/repline.cabal
@@ -1,5 +1,5 @@
 name:                repline
-version:             0.2.1.0
+version:             0.2.2.0
 synopsis:            Haskeline wrapper for GHCi-like REPL interfaces.
 license:             MIT
 license-file:        LICENSE
@@ -31,8 +31,10 @@
   build-depends:
     base       >= 4.6 && <5.0,
     containers >= 0.5 && <0.7,
-    fail       >= 4.9 && <4.10,
+    exceptions >= 0.10 && < 0.11,
     mtl        >= 2.2 && <2.3,
     process    >= 1.2 && <2.0,
-    haskeline  >= 0.7 && <0.8
+    haskeline  >= 0.7 && <0.9
+  if !impl(ghc >= 8.0)
+    Build-Depends: fail >= 4.9 && <4.10
   default-language:    Haskell2010
diff --git a/src/System/Console/Repline.hs b/src/System/Console/Repline.hs
--- a/src/System/Console/Repline.hs
+++ b/src/System/Console/Repline.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE RecordWildCards #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE TypeSynonymInstances #-}
@@ -104,9 +105,16 @@
 -}
 
 module System.Console.Repline (
+  -- * Repline Monad
   HaskelineT,
   runHaskelineT,
 
+  -- * Toplevel
+  evalRepl,
+  ReplOpts(..),
+  evalReplOpts,
+
+  -- * Repline Types
   Cmd,
   Options,
   WordCompleter,
@@ -114,20 +122,20 @@
   CompleterStyle(..),
   Command,
 
+  -- * Completers
   CompletionFunc, -- re-export
 
   wordCompleter,
   listCompleter,
   fileCompleter,
   listWordCompleter,
-
   runMatcher,
-  evalRepl,
+  trimComplete,
+
+  -- * Utilities
   abort,
   tryAction,
   dontCrash,
-
-  trimComplete,
 ) where
 
 import System.Console.Haskeline.Completion
@@ -147,6 +155,7 @@
 newtype HaskelineT (m :: * -> *) a = HaskelineT { unHaskeline :: H.InputT m a }
  deriving (Monad, Functor, Applicative, MonadIO, MonadException, MonadTrans, MonadHaskeline)
 
+-- | Run HaskelineT monad
 runHaskelineT :: MonadException m => H.Settings m -> HaskelineT m a -> m a
 runHaskelineT s m = H.runInputT s (H.withInterrupt (unHaskeline m))
 
@@ -183,11 +192,19 @@
 -- Repl
 -------------------------------------------------------------------------------
 
+-- | Command function synonym
 type Cmd m = [String] -> m ()
+
+-- | Options function synonym
 type Options m = [(String, Cmd m)]
+
+-- | Command function synonym
 type Command m = String -> m ()
 
+-- | Word completer
 type WordCompleter m = (String -> m [String])
+
+-- | Line completer
 type LineCompleter m = (String -> String -> m [Completion])
 
 -- | Wrap a HasklineT action so that if an interrupt is thrown the shell continues as normal.
@@ -205,10 +222,10 @@
 
 -- | Completion loop.
 replLoop :: (Functor m, MonadException m)
-         => HaskelineT m String
-         -> Command (HaskelineT m)
-         -> Options (HaskelineT m)
-         -> Maybe Char
+         => HaskelineT m String -- ^ banner function
+         -> Command (HaskelineT m) -- ^ command function
+         -> Options (HaskelineT m) -- ^ options function
+         -> Maybe Char             -- ^ options prefix
          -> HaskelineT m ()
 replLoop banner cmdM opts optsPrefix = loop
   where
@@ -241,6 +258,31 @@
   | s `isPrefixOf` x = m args
   | otherwise = optMatcher s xs args
 
+-------------------------------------------------------------------------------
+-- Toplevel
+-------------------------------------------------------------------------------
+
+-- | REPL Options datatype
+data ReplOpts m = ReplOpts {
+    banner      :: HaskelineT m String    -- ^ Banner
+  , command     :: Command (HaskelineT m) -- ^ Command function
+  , options     :: Options (HaskelineT m) -- ^ Options list and commands
+  , prefix      :: Maybe Char             -- ^ Optional command prefix ( passing Nothing ignores the Options argument )
+  , tabComplete :: CompleterStyle m       -- ^ Tab completion function
+  , initialiser :: HaskelineT m ()        -- ^ Initialiser
+  }
+
+-- | Evaluate the REPL logic into a MonadException context from the ReplOpts
+-- configuration.
+evalReplOpts :: (Functor m, MonadException m) => ReplOpts m -> m ()
+evalReplOpts (ReplOpts {..}) = evalRepl
+  banner
+  command
+  options
+  prefix
+  tabComplete
+  initialiser
+
 -- | Evaluate the REPL logic into a MonadException context.
 evalRepl :: (Functor m, MonadException m)  -- Terminal monad ( often IO ).
          => HaskelineT m String            -- ^ Banner
@@ -248,7 +290,7 @@
          -> Options (HaskelineT m)         -- ^ Options list and commands
          -> Maybe Char                     -- ^ Optional command prefix ( passing Nothing ignores the Options argument )
          -> CompleterStyle m               -- ^ Tab completion function
-         -> HaskelineT m a                 -- ^ Initializer
+         -> HaskelineT m a                 -- ^ Initialiser
          -> m ()
 evalRepl banner cmd opts optsPrefix comp initz = runHaskelineT _readline (initz >> monad)
   where
@@ -263,8 +305,6 @@
 -- Completions
 -------------------------------------------------------------------------------
 
---type CompletionFunc m = (String, String) -> m (String, [Completion])
-
 data CompleterStyle m
   = Word (WordCompleter m)       -- ^ Completion function takes single word.
   | Word0 (WordCompleter m)      -- ^ Completion function takes single word ( no space ).
@@ -274,6 +314,7 @@
       (CompletionFunc m)
       [(String, CompletionFunc m)] -- ^ Conditional tab completion based on prefix.
 
+-- | Make a completer function from a completion type
 mkCompleter :: MonadIO m => CompleterStyle m -> CompletionFunc m
 mkCompleter (Word f)          = completeWord (Just '\\') " \t()[]" (_simpleComplete f)
 mkCompleter (Word0 f)         = completeWord (Just '\\') " \t()[]" (_simpleCompleteNoSpace f)
@@ -283,7 +324,7 @@
 
 -- haskeline takes the first argument as the reversed string, don't know why
 unRev0 :: LineCompleter m -> LineCompleter m
-unRev0 f x y = f (reverse x) y
+unRev0 f x = f (reverse x)
 
 trimComplete :: String -> Completion -> Completion
 trimComplete prefix (Completion a b c) = Completion (drop (length prefix) a) b c
@@ -297,15 +338,18 @@
 completionNoSpace :: String -> Completion
 completionNoSpace str = Completion str str False
 
+-- | Word completer function
 wordCompleter :: Monad m => WordCompleter m -> CompletionFunc m
 wordCompleter f (start, n) = completeWord (Just '\\') " \t()[]" (_simpleComplete f) (start, n)
 
+-- | List completer function
 listCompleter :: Monad m => [String] -> CompletionFunc m
 listCompleter names (start, n) = completeWord (Just '\\') " \t()[]" (_simpleComplete (complete_aux names)) (start, n)
 
 listWordCompleter :: Monad m => [String] -> WordCompleter m
 listWordCompleter = complete_aux
 
+-- | File completer function
 fileCompleter :: MonadIO m => CompletionFunc m
 fileCompleter = completeFilename
 
@@ -321,8 +365,10 @@
   | x `isPrefixOf` s = f args
   | otherwise = completeMatcher def s xs args
 
-runMatcher :: Monad m => [(String, CompletionFunc m)]
-                      -> CompletionFunc m
-                      -> CompletionFunc m
+-- | Return a completion function a line fragment
+runMatcher
+  :: Monad m => [(String, CompletionFunc m)]
+  -> CompletionFunc m
+  -> CompletionFunc m
 runMatcher opts def (start, n) =
   completeMatcher def (n ++ reverse start) opts (start, n)
