diff --git a/bytestringparser-temporary.cabal b/bytestringparser-temporary.cabal
--- a/bytestringparser-temporary.cabal
+++ b/bytestringparser-temporary.cabal
@@ -1,5 +1,5 @@
 name:            bytestringparser-temporary
-version:         0.3.0
+version:         0.4.0
 license:         BSD3
 license-file:    LICENSE
 category:        Text, Parsing
diff --git a/src/Data/ParserCombinators/Attoparsec/Char8.hs b/src/Data/ParserCombinators/Attoparsec/Char8.hs
--- a/src/Data/ParserCombinators/Attoparsec/Char8.hs
+++ b/src/Data/ParserCombinators/Attoparsec/Char8.hs
@@ -22,12 +22,14 @@
     , parse
     , parseAt
     , parseTest
+    , subParse
 
     -- * Combinators
     , (<?>)
 
     -- * Things vaguely like those in @Parsec.Combinator@ (and @Parsec.Prim@)
     , try
+    , choice
     , manyTill
     , eof
     , notFollowedBy
@@ -53,8 +55,10 @@
 
     -- * Parser converters.
     , eitherP
+    , eitherF
 
     -- * Miscellaneous functions.
+    , err
     , getInput
     , getConsumed
     , takeWhile
@@ -79,8 +83,9 @@
 import qualified Data.ParserCombinators.Attoparsec.Internal as I
 import Data.ParserCombinators.Attoparsec.Internal
     (Parser, ParseError, (<?>), parse, parseAt, parseTest, try, manyTill, eof,
-     skipMany, skipMany1, count, lookAhead, peek, sepBy, sepBy1,
-     eitherP, getInput, getConsumed, takeAll, notEmpty, match, notFollowedBy)
+     skipMany, skipMany1, count, lookAhead, peek, sepBy, sepBy1, subParse,
+     eitherP, eitherF, getInput, getConsumed, takeAll, notEmpty, match, err,
+     notFollowedBy, choice)
 import Prelude hiding (takeWhile)
 
 -- | Character parser.
diff --git a/src/Data/ParserCombinators/Attoparsec/Internal.hs b/src/Data/ParserCombinators/Attoparsec/Internal.hs
--- a/src/Data/ParserCombinators/Attoparsec/Internal.hs
+++ b/src/Data/ParserCombinators/Attoparsec/Internal.hs
@@ -22,12 +22,14 @@
     , parse
     , parseAt
     , parseTest
+    , subParse
 
     -- * Combinators
     , (<?>)
 
     -- * Things vaguely like those in @Parsec.Combinator@ (and @Parsec.Prim@)
     , try
+    , choice
     , manyTill
     , eof
     , notFollowedBy
@@ -49,8 +51,10 @@
 
     -- * Parser converters.
     , eitherP
+    , eitherF
 
     -- * Miscellaneous functions.
+    , err
     , getInput
     , getConsumed
     , takeWhile
@@ -235,6 +239,10 @@
           Left (_, msgs) -> Left (sb +: lb, msgs)
           ok -> ok
 
+-- | Try multiple parsers.
+choice :: [Parser a] -> Parser a
+choice = foldr1 (<|>)
+
 -- | Detect 'end of file'.
 eof :: Parser ()
 eof = Parser $ \s@(S sb lb _) -> if SB.null sb && LB.null lb
@@ -244,8 +252,8 @@
 notFollowedBy :: Parser a -> Parser ()
 notFollowedBy p = Parser $ \s@(S sb lb _) ->
                   case unParser p s of
-                    Left (_, msgs) -> Right ((), s)
-                    ok -> Left (sb +: lb, [])
+                    Left (_, _) -> Right ((), s)
+                    _ -> Left (sb +: lb, [])
 
 takeAll :: Parser LB.ByteString
 takeAll = Parser $ \(S sb lb n) ->
@@ -328,14 +336,23 @@
 eitherP a b = (Left <$> a) <|> (Right <$> b)
 {-# INLINE eitherP #-}
 
+eitherF :: Parser a -> Parser (Either (LB.ByteString, [String]) a) 
 eitherF p = Parser $ \s ->
             case unParser p s of
               Right (m, s') -> Right (Right m, s')
               Left err -> Right (Left err, s)
 {-# INLINE eitherF #-}
 
-err strings = Parser $ \s@(S sb lb n) -> Left (sb +: lb, strings)
+err :: [String] -> Parser a
+err strings = Parser $ \(S sb lb _) -> Left (sb +: lb, strings)
 {-# INLINE err #-}
+
+subParse :: Parser a -> LB.ByteString -> Parser a
+subParse p bs = Parser $ \s@(S sb lb _) ->
+                case unParser p (mkState bs 0) of
+                  Left (_, msg) -> Left (sb +: lb, "sub parse failure" : msg)
+                  Right (x, _) -> Right (x, s)
+{-# INLINE subParse #-}
 
 peek :: Parser a -> Parser (Maybe a)
 peek p = Parser $ \s ->
