diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,8 @@
+v0.3.0.1
+
+ * Parser is now wrapped in Codensity, as the performance impact is minimal
+ * Prototype benchmark suite
+
+v0.2.0
+
+ * Dropped the lens dependency, for microlens
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,24 @@
+[![Build Status](https://travis-ci.org/bartavelle/fastparser.svg?branch=master)](https://travis-ci.org/bartavelle/fastparser)
+
+
+A very simple, backtracking, fast parser combinator library.
+
+It is measurably faster than [attoparsec](https://hackage.haskell.org/package/attoparsec) (36% in [this use case](https://hbtvl.banquise.net/posts/2015-12-14-fastParsing03.html)), but only works on strict `ByteString`, lacks many helper functions, and is not resumable.
+It also should consume a tiny bit less memory for equivalent operations.
+
+# When NOT to use fastparser
+
+ * When performance is not the **most** pressing concern.
+ * When you need to parse anything else but strict `ByteString`.
+ * When you need to use a battle-tested library. While very simple, and in constant use by me, this package is still quite experimental.
+ * When you need to parse large inputs that are not easily cut into many smaller pieces that can be parsed independently.
+
+# How to use fastparser
+
+`fastparser` works well with small pieces, such as individual log file lines. It is recommended to use it with a coroutine library (such as [conduit](http://hackage.haskell.org/package/conduit) or [pipe](http://hackage.haskell.org/package/pipes)), so that the input could be incrementaly consumed, cut into individual records, all of which would end up parsed independently.
+
+One such setup, with the `conduit` ecosystem, would look like:
+
+    sourceFile "/tmp/foo" .| Data.Conduit.Binary.lines .| CL.map (parseOnly parser) .| ...
+
+Other than that, `fastparser` is fairly close to any other parser combinators library.
diff --git a/bench/timestamps.hs b/bench/timestamps.hs
new file mode 100644
--- /dev/null
+++ b/bench/timestamps.hs
@@ -0,0 +1,13 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Main where
+
+import ByteString.Parser.Fast
+import Criterion
+import Criterion.Main
+import qualified Data.ByteString as BS
+
+timestampBench :: BS.ByteString -> Benchmark
+timestampBench b = bench (show b) $ nf ((\(Right a) -> a) . parseOnly timestamp) b
+
+main :: IO ()
+main = defaultMain [timestampBench "2016-12-27+09:58:09.9634133070+CET", timestampBench "2014-07-23+00:16:31.0000000000+CEST"]
diff --git a/fastparser.cabal b/fastparser.cabal
--- a/fastparser.cabal
+++ b/fastparser.cabal
@@ -1,5 +1,5 @@
 name:                fastparser
-version:             0.3.0
+version:             0.3.0.1
 synopsis:            A fast, but bare bones, bytestring parser combinators library.
 description:         Please see README.md
 homepage:            https://github.com/bartavelle/fastparser#readme
@@ -10,22 +10,36 @@
 copyright:           Simon Marechal
 category:            Parsing
 build-type:          Simple
--- extra-source-files:
+extra-source-files:  CHANGELOG.md, README.md
 cabal-version:       >=1.10
+Tested-With:         GHC == 7.10.2, GHC == 8.0.2, GHC == 8.2.1
 
 library
   hs-source-dirs:      src
   exposed-modules:     ByteString.Parser.Fast
-  build-depends:       base >= 4.7 && < 5
-                     , bytestring == 0.10.*
-                     , thyme == 0.3.*
-                     , vector-space == 0.10.*
-                     , microlens == 0.4.*
+  build-depends:       base              >= 4.7 && < 5
+                     , bytestring
+                     , thyme             == 0.3.*
+                     , vector-space      >= 0.10 && < 1
+                     , microlens         == 0.4.*
                      , bytestring-lexing == 0.5.*
-                     , containers == 0.5.*
+                     , containers        == 0.5.*
+                     , kan-extensions    == 5.*
+                     , transformers      >= 0.4
   ghc-options:         -O2 -Wall
   default-language:    Haskell2010
 
 source-repository head
   type:     git
   location: https://github.com/bartavelle/fastparser
+
+benchmark timestamps
+  type:                exitcode-stdio-1.0
+  main-is:             timestamps.hs
+  hs-source-dirs:      bench
+  build-depends:       base >= 4.7 && < 5
+                     , criterion
+                     , fastparser
+                     , bytestring
+  ghc-options:         -O2 -Wall
+  default-language:    Haskell2010
diff --git a/src/ByteString/Parser/Fast.hs b/src/ByteString/Parser/Fast.hs
--- a/src/ByteString/Parser/Fast.hs
+++ b/src/ByteString/Parser/Fast.hs
@@ -48,7 +48,7 @@
 {-# LANGUAGE OverloadedStrings #-}
 module ByteString.Parser.Fast
   (
-  Parser(..), parseOnly,
+  Parser, ParserM(..), parseOnly,
   -- * Error handling
   ParseError(..), ErrorItem(..), ueof, ufail, parseError,
   -- * Parsing numerical values
@@ -76,8 +76,11 @@
 import Data.Thyme
 import Data.Thyme.Time.Core
 import Lens.Micro
-
+import Data.Monoid
 import qualified Data.ByteString.Lex.Fractional as L
+import Control.Monad.Codensity (Codensity, lowerCodensity)
+import Control.Monad.Trans.Class (lift)
+import Prelude
 
 -- | A parser, church encoded. The arguments to the wrapped function are:
 --
@@ -85,7 +88,7 @@
 --  * A function that handles parse errors.
 --  * A function that handles success, taking as argument the remaining
 --  input and the parser result.
-newtype Parser a
+newtype ParserM a
   = Parser {
            runParser :: forall r. BS.ByteString
                      -> (ParseError -> r)
@@ -93,7 +96,9 @@
                      -> r
   } deriving Functor
 
-instance Applicative Parser where
+type Parser = Codensity ParserM
+
+instance Applicative ParserM where
     pure a = Parser $ \b _ s -> s b a
     {-# INLINE pure #-}
     Parser pf <*> Parser px = Parser $ \input failure success ->
@@ -101,20 +106,20 @@
         in  pf input failure succ'
     {-# INLINE (<*>) #-}
 
-instance Alternative Parser where
+instance Alternative ParserM where
     empty = Parser (\_ failure _ -> failure mempty)
     {-# INLINE empty #-}
     Parser a <|> Parser b = Parser $ \input failure success -> a input (\rr ->  b input (failure . mappend rr) success) success
     {-# INLINE (<|>) #-}
 
-instance Monad Parser where
+instance Monad ParserM where
     fail s = Parser $ \_ failure _ -> failure (ufail s)
     m >>= k = Parser $ \input failure success ->
         let succ' input' a = runParser (k a) input' failure success
         in  runParser m input failure succ'
     {-# INLINE (>>=) #-}
 
-instance MonadPlus Parser
+instance MonadPlus ParserM
 
 data ErrorItem
     = Tokens BS.ByteString
@@ -154,7 +159,7 @@
 -- It works well with the
 -- [bytestring-lexing](https://hackage.haskell.org/package/bytestring-lexing) library.
 wlex :: (BS.ByteString -> Maybe (a, BS.ByteString)) -> Parser a
-wlex p = Parser $ \i failure success -> case p i of
+wlex p = lift $ Parser $ \i failure success -> case p i of
                                             Nothing -> failure mempty
                                             Just (a, i') -> success i' a
 {-# INLINABLE wlex #-}
@@ -223,25 +228,27 @@
 
 -- | Consumes n bytes of input
 takeN :: Int -> Parser BS.ByteString
-takeN n = Parser $ \input failure success -> if BS.length input < n
-                                                 then failure ueof
-                                                 else let (a,rest) = BS.splitAt n input
-                                                      in  success rest a
+takeN n = lift $ Parser $ \input failure success
+    -> if BS.length input < n
+         then failure ueof
+         else let (a,rest) = BS.splitAt n input
+              in  success rest a
 
 -- | Parses any character.
 anyChar :: Parser Char
-anyChar = Parser $ \input failure success -> if BS.null input then failure ueof else success (BS8.tail input) (BS8.head input)
+anyChar = lift $ Parser $ \input failure success -> if BS.null input then failure ueof else success (BS8.tail input) (BS8.head input)
 
 -- | Parses a specific character.
 char :: Char -> Parser ()
-char c = Parser $ \input failure success -> if BS.null input then failure ueof else if BS8.head input == c then success (BS.tail input) () else failure (parseError (BS8.take 1 input) (BS8.singleton c))
+char c = lift $ Parser $ \input failure success -> if BS.null input then failure ueof else if BS8.head input == c then success (BS.tail input) () else failure (parseError (BS8.take 1 input) (BS8.singleton c))
 {-# INLINE char #-}
 
 -- | Parses the supplied string.
 string :: BS.ByteString -> Parser ()
-string s = Parser $ \input failure success -> if s `BS.isPrefixOf` input
-                                                  then success (BS.drop (BS.length s) input) ()
-                                                  else failure (parseError (BS.take (BS.length s) input) s)
+string s = lift $ Parser $ \input failure success
+    -> if s `BS.isPrefixOf` input
+          then success (BS.drop (BS.length s) input) ()
+          else failure (parseError (BS.take (BS.length s) input) s)
 
 -- | Parses strings between double quotes. This functions handles the
 -- following escape sequences: \\r, \\n, \\t, \\a, \\b, \\", \\\\.
@@ -277,42 +284,47 @@
 {-# INLINE scientific #-}
 
 charTakeWhile1 :: (Char -> Bool) -> Parser BS.ByteString
-charTakeWhile1 prd = Parser $ \s failure success -> case BS8.span prd s of
-                                                    (a,b) -> if BS.null a then failure (ParseError (S.singleton (Tokens (BS.take 1 s))) mempty) else success b a
+charTakeWhile1 prd = lift $ Parser $ \s failure success ->
+    case BS8.span prd s of
+      (a,b) -> if BS.null a then failure (ParseError (S.singleton (Tokens (BS.take 1 s))) mempty) else success b a
 {-# INLINE charTakeWhile1 #-}
 
 takeWhile1 :: (Word8 -> Bool) -> Parser BS.ByteString
-takeWhile1 prd = Parser $ \s failure success -> case BS.span prd s of
-                                                    (a,b) -> if BS.null a then failure (ParseError (S.singleton (Tokens (BS.take 1 s))) mempty) else success b a
+takeWhile1 prd = lift $ Parser $ \s failure success ->
+    case BS.span prd s of
+      (a,b) -> if BS.null a then failure (ParseError (S.singleton (Tokens (BS.take 1 s))) mempty) else success b a
 {-# INLINE takeWhile1 #-}
 
 -- | Consumes the input as long as the predicate remains true.
 charTakeWhile :: (Char -> Bool) -> Parser BS.ByteString
-charTakeWhile prd = Parser $ \s _ success -> case BS8.span prd s of
-                                             (a,b) -> success b a
+charTakeWhile prd = lift $ Parser $ \s _ success ->
+    case BS8.span prd s of
+      (a,b) -> success b a
 {-# INLINE charTakeWhile #-}
 
 -- | Consumes the input as long as the predicate remains true.
 takeWhile :: (Word8 -> Bool) -> Parser BS.ByteString
-takeWhile prd = Parser $ \s _ success -> case BS.span prd s of
-                                             (a,b) -> success b a
+takeWhile prd = lift $ Parser $ \s _ success ->
+  case BS.span prd s of
+    (a,b) -> success b a
 {-# INLINE takeWhile #-}
 
 -- | Discards the input as long as the predicate remains true.
 skipWhile :: (Word8 -> Bool) -> Parser ()
-skipWhile prd = Parser $ \s _ success -> success (BS.dropWhile prd s) ()
+skipWhile prd = lift $ Parser $ \s _ success -> success (BS.dropWhile prd s) ()
 {-# INLINE skipWhile #-}
 
 -- | Runs the parser. Will return a parse error if the parser fails
 -- or if the input is not completely consumed.
 parseOnly :: Parser a -> BS.ByteString -> Either ParseError a
-parseOnly (Parser p) s = p s Left $ \b a -> if BS.null b
+parseOnly prs s = case lowerCodensity prs of
+                  Parser p -> p s Left $ \b a -> if BS.null b
                                               then Right a
                                               else Left (ParseError (S.singleton (Tokens (BS.take 1 b))) mempty)
 
 -- | Parses the remaining input.
 remaining :: Parser BS.ByteString
-remaining = Parser $ \input _ success -> success BS.empty input
+remaining = lift $ Parser $ \input _ success -> success BS.empty input
 
 -- | Parses days, with format YYYY-MM-DD
 parseYMD :: Parser Day
