diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -55,13 +55,13 @@
 |sexp/attoparsec              | 21.82 ms   |
 |sexp/megaparsec              | 59.60 ms   |
 |sexp/parsec                  | 79.81 ms   |
-|long keyword/fpbasic         | 96.95 μs   |
-|long keyword/fpstateful      | 95.30 μs   |
+|long keyword/fpbasic         | 0.1 ms     |
+|long keyword/fpstateful      | 0.1 ms     |
 |long keyword/attoparsec      | 2.43 ms    |
-|long keyword/megaparsec      | 5.196 ms   |
+|long keyword/megaparsec      | 5.2 ms     |
 |long keyword/parsec          | 10.02 ms   |
-|numeral csv/fpbasic          | 715.2 μs   |
-|numeral csv/fpstateful       | 555.0 μs   |
+|numeral csv/fpbasic          | 0.72 ms    |
+|numeral csv/fpstateful       | 0.56 ms    |
 |numeral csv/attoparsec       | 10.52 ms   |
 |numeral csv/megaparsec       | 19.77 ms   |
 |numeral csv/parsec           | 26.46 ms   |
diff --git a/flatparse.cabal b/flatparse.cabal
--- a/flatparse.cabal
+++ b/flatparse.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           flatparse
-version:        0.5.0.2
+version:        0.5.1.0
 synopsis:       High-performance parsing from strict bytestrings
 description:    @Flatparse@ is a high-performance parsing library for strict bytestring input. See the README for more information:
                 <https://github.com/AndrasKovacs/flatparse>.
diff --git a/src/FlatParse/Basic/Base.hs b/src/FlatParse/Basic/Base.hs
--- a/src/FlatParse/Basic/Base.hs
+++ b/src/FlatParse/Basic/Base.hs
@@ -188,7 +188,7 @@
 --   the usual `chainl` function from the parsec libraries!
 chainl :: (b -> a -> b) -> ParserT st e b -> ParserT st e a -> ParserT st e b
 chainl f start elem = start >>= go where
-  go b = do {!a <- elem; go $! f b a} <|> pure b
+  go b = withOption elem (\ !a -> go $! f b a) (pure b)
 {-# inline chainl #-}
 
 -- | An analogue of the list `foldr` function: parse zero or more @a@-s, terminated by a @b@, and
diff --git a/src/FlatParse/Basic/Parser.hs b/src/FlatParse/Basic/Parser.hs
--- a/src/FlatParse/Basic/Parser.hs
+++ b/src/FlatParse/Basic/Parser.hs
@@ -10,6 +10,7 @@
   -- * Parser
     ParserT(..)
   , Parser, ParserIO, ParserST
+  , pureLazy
 
   -- * Result
   , type Res#
@@ -55,7 +56,7 @@
 
 instance Functor (ParserT st e) where
   fmap f (ParserT g) = ParserT \fp eob s st -> case g fp eob s st of
-    OK# st' a s -> OK# st' (f $! a) s
+    OK# st' a s -> let !b = f a in OK# st' b s
     x           -> unsafeCoerce# x
   {-# inline fmap #-}
 
@@ -65,11 +66,11 @@
   {-# inline (<$) #-}
 
 instance Applicative (ParserT st e) where
-  pure a = ParserT \fp eob s st -> OK# st a s
+  pure !a = ParserT \fp eob s st -> OK# st a s
   {-# inline pure #-}
   ParserT ff <*> ParserT fa = ParserT \fp eob s st -> case ff fp eob s st of
     OK# st' f s -> case fa fp eob s st' of
-      OK# st'' a s -> OK# st'' (f $! a) s
+      OK# st'' a s -> let !b = f a in OK# st'' b s
       x            -> unsafeCoerce# x
     x           -> unsafeCoerce# x
   {-# inline (<*>) #-}
@@ -83,6 +84,11 @@
     OK# st' _a s -> fb fp eob s st'
     x            -> unsafeCoerce# x
   {-# inline (*>) #-}
+
+-- | Same as `pure` for `ParserT` except that it does not force the returned value.
+pureLazy :: a -> ParserT st e a
+pureLazy a = ParserT \fp eob s st -> OK# st a s
+{-# inline pureLazy #-}
 
 instance Monad (ParserT st e) where
   return = pure
diff --git a/src/FlatParse/Stateful/Base.hs b/src/FlatParse/Stateful/Base.hs
--- a/src/FlatParse/Stateful/Base.hs
+++ b/src/FlatParse/Stateful/Base.hs
@@ -190,7 +190,7 @@
 --   the usual `chainl` function from the parsec libraries!
 chainl :: (b -> a -> b) -> ParserT st r e b -> ParserT st r e a -> ParserT st r e b
 chainl f start elem = start >>= go where
-  go b = do {!a <- elem; go $! f b a} <|> pure b
+  go b = withOption elem (\ !a -> go $! f b a) (pure b)
 {-# inline chainl #-}
 
 -- | An analogue of the list `foldr` function: parse zero or more @a@-s, terminated by a @b@, and
diff --git a/src/FlatParse/Stateful/Parser.hs b/src/FlatParse/Stateful/Parser.hs
--- a/src/FlatParse/Stateful/Parser.hs
+++ b/src/FlatParse/Stateful/Parser.hs
@@ -10,6 +10,7 @@
   -- * Parser
     ParserT(..)
   , Parser, ParserIO, ParserST
+  , pureLazy
 
   -- ** Result
   , type Res#
@@ -56,7 +57,7 @@
 
 instance Functor (ParserT st r e) where
   fmap f (ParserT g) = ParserT \fp !r eob s n st -> case g fp r eob s n st of
-    OK# st' a s n -> OK# st' (f $! a) s n
+    OK# st' a s n -> let !b = f a in OK# st' b s n
     x             -> unsafeCoerce# x
   {-# inline fmap #-}
 
@@ -66,11 +67,11 @@
   {-# inline (<$) #-}
 
 instance Applicative (ParserT st r e) where
-  pure a = ParserT \_fp !_r _eob s n st -> OK# st a s n
+  pure !a = ParserT \_fp !_r _eob s n st -> OK# st a s n
   {-# inline pure #-}
   ParserT ff <*> ParserT fa = ParserT \fp !r eob s n st -> case ff fp r eob s n st of
     OK# st' f s n -> case fa fp r eob s n st' of
-      OK# st'' a s n -> OK# st'' (f $! a) s n
+      OK# st'' a s n -> let b = f a in OK# st'' b s n
       x              -> unsafeCoerce# x
     x             -> unsafeCoerce# x
   {-# inline (<*>) #-}
@@ -84,6 +85,11 @@
     OK# st' _a s n -> fb fp r eob s n st'
     x              -> unsafeCoerce# x
   {-# inline (*>) #-}
+
+-- | Same as `pure` for `ParserT` except that it does not force the returned value.
+pureLazy :: a -> ParserT st r e a
+pureLazy a = ParserT \_fp !_r _eob s n st -> OK# st a s n
+{-# inline pureLazy #-}
 
 instance Monad (ParserT st r e) where
   return = pure
