diff --git a/Setup.hs b/Setup.hs
deleted file mode 100644
--- a/Setup.hs
+++ /dev/null
@@ -1,2 +0,0 @@
-import Distribution.Simple
-main = defaultMain
diff --git a/changelog.txt b/changelog.txt
--- a/changelog.txt
+++ b/changelog.txt
@@ -68,3 +68,6 @@
   + let 'parse' throw errors by default
   + changed priorities of operator tables to doubles 
   + removed need to specify associativity of prefix operators in operator table
+
+0.4.0.12 -> 0.4.0.13
+  + export 'lexerEither' that produces an 'Either' value with either an error or a list of tokens
diff --git a/gll.cabal b/gll.cabal
--- a/gll.cabal
+++ b/gll.cabal
@@ -3,7 +3,7 @@
 
 -- The name of the package.
 name:                gll
-version:             0.4.0.12
+version:             0.4.0.13
 synopsis:            GLL parser with simple combinator interface 
 license:             BSD3
 license-file:        LICENSE
@@ -12,8 +12,8 @@
 category:            Compilers
 build-type:          Simple 
 cabal-version:       >=1.22
-tested-with:         GHC == 8.0.1, GHC == 8.0.2 
-copyright:           Copyright (C) 2015 L. Thomas van Binsbergen
+tested-with:         GHC >= 8.2.1 && <= 8.6, GHC == 8.8.3
+copyright:           Copyright (C) 2015-2020 L. Thomas van Binsbergen
 stability:           experimental
 description:         
 
@@ -48,9 +48,9 @@
                         , text
                         , regex-applicative >= 0.3
                         , time >= 1.8
-                        , random-strings >= 0.1.1.0
     exposed-modules :     GLL.Combinators.Interface
                         , GLL.Combinators.BinaryInterface
+                        , GLL.GrammarCombinators
                         , GLL.Combinators
                         , GLL.Combinators.Test.Interface
                         , GLL.Combinators.Test.BinaryInterface
diff --git a/src/GLL/Combinators/BinaryInterface.hs b/src/GLL/Combinators/BinaryInterface.hs
--- a/src/GLL/Combinators/BinaryInterface.hs
+++ b/src/GLL/Combinators/BinaryInterface.hs
@@ -29,7 +29,7 @@
     -- * Running a parser 
     grammarOf, parse, printParseData, evaluatorWithParseData,
     -- **  Running a parser with options
-    parseWithOptions, parseWithParseOptions, printEvalDataWithOptions, printParseDataWithOptions, evaluatorWithParseDataAndOptions,printGrammarData,
+    parseWithOptions, parseWithParseOptions, printParseDataWithOptions, evaluatorWithParseDataAndOptions,printGrammarData,
     -- *** Possible options
     CombinatorOptions, CombinatorOption, 
              GLL.Combinators.Options.maximumErrors, throwErrors, 
diff --git a/src/GLL/Combinators/Interface.hs b/src/GLL/Combinators/Interface.hs
--- a/src/GLL/Combinators/Interface.hs
+++ b/src/GLL/Combinators/Interface.hs
@@ -202,7 +202,7 @@
     -- * Running a parser 
     grammarOf, parse, printParseData, evaluatorWithParseData,
     -- **  Running a parser with options
-    parseWithOptions, parseWithParseOptions, printEvalDataWithOptions, printParseDataWithOptions, evaluatorWithParseDataAndOptions, printGrammarData,
+    parseWithOptions, parseWithParseOptions, printParseDataWithOptions, evaluatorWithParseDataAndOptions, printGrammarData,
     -- *** Possible options
     CombinatorOptions, CombinatorOption, 
              GLL.Combinators.Options.maximumErrors, throwErrors, 
@@ -217,7 +217,7 @@
     -- ** Builtin lexers.
     default_lexer, 
     -- *** Lexer settings
-        lexer, LexerSettings(..), emptyLanguage,
+        lexer, lexerEither, LexerSettings(..), emptyLanguage,
     -- * Derived combinators
     mkNt, 
     -- *** Ignoring semantic results
@@ -318,41 +318,6 @@
           endTime <- getCurrentTime
           putStrLn $ "semantic phase:       " ++ show (diffUTCTime endTime startTime')-}
           putStrLn $ "total time:           " ++ show (diffUTCTime endTime startTime)
-
--- | Variant of 'printParseData' which can be controlled by 'ParseOption's
-printEvalDataWithOptions :: (Parseable t, IsSymbExpr s, Show a) => ParseOptions -> CombinatorOptions -> s t a -> [t] -> IO ()
-printEvalDataWithOptions popts opts p' input = 
-    let SymbExpr (Nt start,vpa2,vpa3) = mkRule ("__Start" <:=> OO [id <$$> p'])
-        rules       = vpa2 M.empty
-        grammar     = (start, [ p | (_, alts) <- M.assocs rules, p <- alts ])
-        parse_res   = GLL.parseWithOptions (popts ++ [packedNodesOnly,strictBinarisation]) grammar input
-        arr         = mkInput input 
-        (_,m)       = A.bounds arr
-    in do let (_,prods) = grammar
-              nt_set = S.fromList [ x | Prod x _ <- prods ]
-          putStrLn $ "#production:          " ++ show (length prods)
-          putStrLn $ "#nonterminals:        " ++ show (length nt_set)
-          putStrLn $ "largest nonterminal:  " ++ show ( 
-            foldr (\x -> max (Data.Text.length x)) 0 nt_set)
-
-          startTime <- getCurrentTime
-          putStrLn $ "#tokens:              " ++ (show m)
-          putStrLn $ "#successes:           " ++ (show $ res_successes parse_res)
-          endTime <- getCurrentTime
-          putStrLn $ "recognition time:     " ++ show (diffUTCTime endTime startTime)
-          startTime' <- getCurrentTime
-          putStrLn $ "#descriptors          " ++ (show $ nr_descriptors parse_res)
-          putStrLn $ "#EPNs                 " ++ (show $ nr_packed_node_attempts parse_res) 
-          endTime <- getCurrentTime
-          putStrLn $ "parse-data time:      " ++ show (diffUTCTime endTime startTime')
-          startTime' <- getCurrentTime
-          as <- vpa3 (runOptions opts) emptyAncestors (sppf_result parse_res) arr 0 m
-          putStrLn $ "ambiguous?:           " ++ show (length as > 1)
-          when (not (null as)) (writeFile "/tmp/derivation" (show (head as)))
-          endTime <- getCurrentTime
-          putStrLn $ "semantic phase:       " ++ show (diffUTCTime endTime startTime')
-          putStrLn $ "total time:           " ++ show (diffUTCTime endTime startTime)
-
 
 -- | Print some information 
 evaluatorWithParseData :: (Parseable t, IsSymbExpr s, Show a) => s t a -> [t] -> [a]
diff --git a/src/GLL/Combinators/Lexer.hs b/src/GLL/Combinators/Lexer.hs
--- a/src/GLL/Combinators/Lexer.hs
+++ b/src/GLL/Combinators/Lexer.hs
@@ -1,6 +1,6 @@
 
 module GLL.Combinators.Lexer (
-    default_lexer, lexer, LexerSettings(..), emptyLanguage,
+    default_lexer, lexer, lexerEither, LexerSettings(..), emptyLanguage,
     oneOf, manyOf, someOf, baseToDec,
     ) where
 
@@ -47,18 +47,24 @@
 default_lexer :: SubsumesToken t => String -> [t]
 default_lexer = lexer emptyLanguage 
 
--- | A lexer parameterised by 'LexerSettings'.
+-- | Variant of 'lexerEither' that throws an error or returns the result otherwise
 lexer :: SubsumesToken t => LexerSettings -> String -> [t]
-lexer _ [] = []
-lexer lexsets s
+lexer set inp = case lexerEither set inp of
+  Left err  -> error err
+  Right ts  -> ts
+
+-- | A lexer parameterised by 'LexerSettings'.
+lexerEither :: SubsumesToken t => LexerSettings -> String -> Either String [t]
+lexerEither _ [] = Right []
+lexerEither lexsets s
   | start /= "" && end /= "" && start `isPrefixOf` s = blockState 1 (drop lS s)
   | lComm /= "" && lComm `isPrefixOf` s = case dropWhile ((/=) '\n') s of
-      []      -> []
-      (c:cs)  -> lexer lexsets cs
-  | isWS (head s) = lexer lexsets (dropWhile isWS s)
+      []      -> Right []
+      (c:cs)  -> lexerEither lexsets cs
+  | isWS (head s) = lexerEither lexsets (dropWhile isWS s)
   | otherwise = case findLongestPrefix (lTokens lexsets) s of
-        Just (tok, rest)   -> tok : lexer lexsets rest
-        Nothing            -> error ("lexical error at: " ++ show (take 10 s))
+        Just (tok, rest)   -> fmap (tok :) $ lexerEither lexsets rest
+        Nothing            -> Left ("lexical error at: " ++ show (take 10 s))
   where start = blockCommentOpen lexsets
         end   = blockCommentClose lexsets
         isWS  = whitespace lexsets
@@ -66,9 +72,9 @@
         lS    = length start
         lE    = length end
 
-        blockState :: SubsumesToken t => Int -> String -> [t] 
-        blockState n [] = [] 
-        blockState 0 rest = lexer lexsets rest
+        blockState :: SubsumesToken t => Int -> String -> Either String [t] 
+        blockState n [] = Right [] 
+        blockState 0 rest = lexerEither lexsets rest
         blockState n cs | start `isPrefixOf` cs = blockState (n+1) (drop lS cs)
                     | end `isPrefixOf` cs   = blockState (n-1) (drop lE cs) 
                     | otherwise             = blockState n (tail cs)
diff --git a/src/GLL/GrammarCombinators.hs b/src/GLL/GrammarCombinators.hs
new file mode 100644
--- /dev/null
+++ b/src/GLL/GrammarCombinators.hs
@@ -0,0 +1,8 @@
+
+-- |
+-- "GLL.Combinators" imports "GLL.Combinators.Interface" as the default library.
+module GLL.GrammarCombinators (
+    module GLL.Combinators.Interface 
+    ) where
+
+import GLL.Combinators.Interface
diff --git a/src/GLL/Parseable/Char.hs b/src/GLL/Parseable/Char.hs
--- a/src/GLL/Parseable/Char.hs
+++ b/src/GLL/Parseable/Char.hs
@@ -1,11 +1,11 @@
 
 -- | Exports an instance for 'Parseable' 'Char' 
--- that assumes '$' and '#' never appear in the inpur string.
+-- that assumes '$' and '#' never appear in the input string.
 module GLL.Parseable.Char () where
 
 import GLL.Types.Grammar
 
--- | Assumes '$' and '#' never appear in the inpur string.
+-- | Assumes '$' and '#' never appear in the input string.
 instance Parseable Char where
     eos = '$'
     eps = '#'
