diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,15 @@
+## Parser combinators 0.4.0
+
+* Improved the documentation.
+
+* Re-exported `Control.Applicative.empty` from
+  `Control.Applicative.Combinators`.
+
+* Added the `Control.Monad.Combinators` and
+  `Control.Monad.Combinators.NonEmpty` modules which contain more efficient
+  versions of the combinators from `Control.Applicative.Combinators` and
+  `Control.Applicative.Combinators.NonEmpty` respectively.
+
 ## Parser combinators 0.3.0
 
 * Added the `skipCount` combinator.
diff --git a/Control/Applicative/Combinators.hs b/Control/Applicative/Combinators.hs
--- a/Control/Applicative/Combinators.hs
+++ b/Control/Applicative/Combinators.hs
@@ -12,6 +12,16 @@
 -- commonly used in parsing from "Control.Applicative" with additional
 -- parsing-related comments added.
 --
+-- Due to the nature of the 'Applicative' and 'Alternative' abstractions,
+-- they are prone to memory leaks and not as efficient as their monadic
+-- counterparts. Although all the combinators we provide in this module are
+-- perfectly expressible in terms of 'Applicative' and 'Alternative', please
+-- prefer "Control.Monad.Combinators" instead when possible.
+--
+-- If you wish that the combinators that cannot return empty lists return
+-- values of the 'Data.List.NonEmpty.NonEmpty' data type, use the
+-- "Control.Applicative.Combinators.NonEmpty" module.
+--
 -- === A note on backtracking
 --
 -- Certain parsing libraries, such as Megaparsec, do not backtrack every
@@ -24,10 +34,10 @@
 -- cannot know anything about inner workings of any concrete parsing
 -- library, and so they cannot use @try@.
 --
--- An essential feature of the 'Alternative' type class is the @('<|>')@
+-- The essential feature of the 'Alternative' type class is the @('<|>')@
 -- operator that allows to express choice. In libraries that do not
 -- backtrack everything automatically, the choice operator and everything
--- that is build on top of it require the parser of the left hand side to
+-- that is build on top of it require the parser on the left hand side to
 -- backtrack in order for the alternative branch of parsing to be tried.
 -- Thus it is the responsibility of the programmer to wrap more complex,
 -- composite parsers in @try@ to achieve correct behavior.
@@ -45,6 +55,8 @@
     -- $some
   , optional
     -- $optional
+  , empty
+    -- $empty
 
     -- * Original combinators
   , between
@@ -89,14 +101,14 @@
 -- $many
 --
 -- @'many' p@ applies the parser @p@ /zero/ or more times and returns a list
--- of the returned values of @p@.
+-- of the values returned by @p@.
 --
 -- > identifier = (:) <$> letter <*> many (alphaNumChar <|> char '_')
 
 -- $some
 --
 -- @'some' p@ applies the parser @p@ /one/ or more times and returns a list
--- of the returned values of @p@.
+-- of the values returned by @p@.
 --
 -- > word = some letter
 
@@ -109,6 +121,13 @@
 --
 -- See also: 'option'.
 
+-- $empty
+--
+-- This parser fails unconditionally without providing any information about
+-- the cause of the failure.
+--
+-- @since 0.4.0
+
 ----------------------------------------------------------------------------
 -- Original combinators
 
@@ -123,14 +142,19 @@
 
 -- | @'choice' ps@ tries to apply the parsers in the list @ps@ in order,
 -- until one of them succeeds. Returns the value of the succeeding parser.
+--
+-- > choice = asum
 
 choice :: (Foldable f, Alternative m) => f (m a) -> m a
 choice = asum
 {-# INLINE choice #-}
 
 -- | @'count' n p@ parses @n@ occurrences of @p@. If @n@ is smaller or equal
--- to zero, the parser equals to @'pure' []@. Returns a list of @n@ values.
+-- to zero, the parser equals to @'pure' []@. Returns a list of @n@ parsed
+-- values.
 --
+-- > count = replicateM
+--
 -- See also: 'skipCount', 'count''.
 
 count :: Applicative m => Int -> m a -> m [a]
@@ -148,7 +172,7 @@
 -- Please note that @m@ /may/ be negative, in this case effect is the same
 -- as if it were equal to zero.
 --
--- See also: 'count'.
+-- See also: 'skipCount', 'count'.
 
 count' :: Alternative m => Int -> Int -> m a -> m [a]
 count' m' n' p = go m' n'
@@ -160,6 +184,8 @@
 {-# INLINE count' #-}
 
 -- | Combine two alternatives.
+--
+-- > eitherP a b = (Left <$> a) <|> (Right <$> b)
 
 eitherP :: Alternative m => m a -> m b -> m (Either a b)
 eitherP a b = (Left <$> a) <|> (Right <$> b)
@@ -205,7 +231,7 @@
 -- consuming input, it returns the value @x@, otherwise the value returned
 -- by @p@.
 --
--- > priority = option 0 (digitToInt <$> digitChar)
+-- > option x p = p <|> pure x
 --
 -- See also: 'optional'.
 
@@ -263,9 +289,11 @@
 skipSome p = p *> skipMany p
 {-# INLINE skipSome #-}
 
--- | @'skipCount' n p@ parses @n@ occurrences of @p@, skipping its result. If
--- @n@ is smaller or equal to zero, the parser equals to @'pure' []@. Returns a
--- list of @n@ values.
+-- | @'skipCount' n p@ parses @n@ occurrences of @p@, skipping its result.
+-- If @n@ is not positive, the parser equals to @'pure' []@. Returns a list
+-- of @n@ values.
+--
+-- > skipCount = replicateM_
 --
 -- See also: 'count', 'count''.
 --
diff --git a/Control/Applicative/Combinators/NonEmpty.hs b/Control/Applicative/Combinators/NonEmpty.hs
--- a/Control/Applicative/Combinators/NonEmpty.hs
+++ b/Control/Applicative/Combinators/NonEmpty.hs
@@ -7,8 +7,8 @@
 -- Stability   :  experimental
 -- Portability :  portable
 --
--- This module provides 'NonEmpty' list variants of some of the functions in
--- "Control.Applicative.Combinators".
+-- The module provides 'NonEmpty' list variants of some of the functions
+-- from "Control.Applicative.Combinators".
 --
 -- @since 0.2.0
 
@@ -26,7 +26,7 @@
 import qualified Data.List.NonEmpty              as NE
 
 -- | @'some' p@ applies the parser @p@ /one/ or more times and returns a
--- list of the returned values of @p@.
+-- list of the values returned by @p@.
 --
 -- > word = some letter
 
diff --git a/Control/Monad/Combinators.hs b/Control/Monad/Combinators.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Combinators.hs
@@ -0,0 +1,324 @@
+-- |
+-- Module      :  Control.Monad.Combinators
+-- Copyright   :  © 2017 Mark Karpov
+-- License     :  BSD 3 clause
+--
+-- Maintainer  :  Mark Karpov <markkarpov92@gmail.com>
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- The module provides more efficient versions of the combinators from
+-- "Control.Applicative.Combinators" defined in terms of 'Monad' and
+-- 'MonadPlus' instead of 'Control.Applicative.Applicative' and
+-- 'Control.Applicative.Alternative'. When there is no difference in
+-- performance we just re-export the combinators from
+-- "Control.Applicative.Combinators".
+--
+-- @since 0.4.0
+
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE CPP          #-}
+
+module Control.Monad.Combinators
+  ( -- * Re-exports from "Control.Applicative"
+    (C.<|>)
+    -- $assocbo
+  , C.optional
+    -- $optional
+  , C.empty
+    -- $empty
+
+    -- * Original combinators
+  , C.between
+  , C.choice
+  , count
+  , count'
+  , C.eitherP
+  , endBy
+  , endBy1
+  , many
+  , manyTill
+  , some
+  , someTill
+  , C.option
+  , sepBy
+  , sepBy1
+  , sepEndBy
+  , sepEndBy1
+  , skipMany
+  , skipSome
+  , skipCount
+  , skipManyTill
+  , skipSomeTill )
+where
+
+import Control.Monad
+import qualified Control.Applicative.Combinators as C
+
+----------------------------------------------------------------------------
+-- Re-exports from "Control.Applicative"
+
+-- $assocbo
+--
+-- This combinator implements choice. The parser @p 'C.<|>' q@ first applies
+-- @p@. If it succeeds, the value of @p@ is returned. If @p@ fails, parser
+-- @q@ is tried.
+
+-- $optional
+--
+-- @'C.optional' p@ tries to apply the parser @p@. It will parse @p@ or
+-- 'Nothing'. It only fails if @p@ fails after consuming input. On success
+-- result of @p@ is returned inside of 'Just', on failure 'Nothing' is
+-- returned.
+--
+-- See also: 'C.option'.
+
+-- $empty
+--
+-- This parser fails unconditionally without providing any information about
+-- the cause of the failure.
+
+----------------------------------------------------------------------------
+-- Original combinators
+
+-- | @'count' n p@ parses @n@ occurrences of @p@. If @n@ is smaller or equal
+-- to zero, the parser equals to @'return' []@. Returns a list of @n@
+-- values.
+--
+-- See also: 'skipCount', 'count''.
+
+count :: Monad m => Int -> m a -> m [a]
+count n' p = liftM ($ []) (go id n')
+  where
+    go f !n =
+      if n <= 0
+        then return f
+        else do
+          x <- p
+          go (f . (x:)) (n - 1)
+{-# INLINE count #-}
+
+-- | @'count'' m n p@ parses from @m@ to @n@ occurrences of @p@. If @n@ is
+-- not positive or @m > n@, the parser equals to @'return' []@. Returns a
+-- list of parsed values.
+--
+-- Please note that @m@ /may/ be negative, in this case effect is the same
+-- as if it were equal to zero.
+--
+-- See also: 'skipCount', 'count'.
+
+count' :: MonadPlus m => Int -> Int -> m a -> m [a]
+count' m' n' p =
+  if n' > 0 && n' >= m'
+    then liftM ($ []) (gom id m')
+    else return []
+  where
+    gom f !m =
+      if m > 0
+        then do
+          x <- p
+          gom (f . (x:)) (m - 1)
+        else god f (if m' <= 0 then n' else n' - m')
+    god f !d =
+      if d > 0
+        then do
+          r <- optional p
+          case r of
+            Nothing -> return f
+            Just  x -> god (f . (x:)) (d - 1)
+        else return f
+{-# INLINE count' #-}
+
+-- | @'endBy' p sep@ parses /zero/ or more occurrences of @p@, separated and
+-- ended by @sep@. Returns a list of values returned by @p@.
+--
+-- > cStatements = cStatement `endBy` semicolon
+
+endBy :: MonadPlus m => m a -> m sep -> m [a]
+endBy p sep = many (p >>= \x -> re x sep)
+{-# INLINE endBy #-}
+
+-- | @'endBy1' p sep@ parses /one/ or more occurrences of @p@, separated and
+-- ended by @sep@. Returns a list of values returned by @p@.
+
+endBy1 :: MonadPlus m => m a -> m sep -> m [a]
+endBy1 p sep = some (p >>= \x -> re x sep)
+{-# INLINE endBy1 #-}
+
+-- | @'many' p@ applies the parser @p@ /zero/ or more times and returns a
+-- list of the values returned by @p@.
+--
+-- > identifier = (:) <$> letter <*> many (alphaNumChar <|> char '_')
+
+many :: MonadPlus m => m a -> m [a]
+many p = liftM ($ []) (go id)
+  where
+    go f = do
+      r <- optional p
+      case r of
+        Nothing -> return f
+        Just  x -> go (f . (x:))
+{-# INLINE many #-}
+
+-- | @'manyTill' p end@ applies parser @p@ /zero/ or more times until parser
+-- @end@ succeeds. Returns the list of values returned by @p@.
+--
+-- See also: 'skipMany', 'skipManyTill'.
+
+manyTill :: MonadPlus m => m a -> m end -> m [a]
+manyTill p end = liftM ($ []) (go id)
+  where
+    go f = do
+      done <- option False (re True end)
+      if done
+        then return f
+        else do
+          x <- p
+          go (f . (x:))
+{-# INLINE manyTill #-}
+
+-- | @'some' p@ applies the parser @p@ /one/ or more times and returns a
+-- list of the values returned by @p@.
+--
+-- > word = some letter
+
+some :: MonadPlus m => m a -> m [a]
+some p = liftM2 (:) p (many p)
+{-# INLINE some #-}
+
+-- | @'someTill' p end@ works similarly to @'manyTill' p end@, but @p@
+-- should succeed at least once.
+--
+-- See also: 'skipSome', 'skipSomeTill'.
+
+someTill :: MonadPlus m => m a -> m end -> m [a]
+someTill p end = liftM2 (:) p (manyTill p end)
+{-# INLINE someTill #-}
+
+-- | @'sepBy' p sep@ parses /zero/ or more occurrences of @p@, separated by
+-- @sep@. Returns a list of values returned by @p@.
+--
+-- > commaSep p = p `sepBy` comma
+
+sepBy :: MonadPlus m => m a -> m sep -> m [a]
+sepBy p sep = do
+  r <- optional p
+  case r of
+    Nothing -> return []
+    Just  x -> liftM (x:) (many (sep >> p))
+{-# INLINE sepBy #-}
+
+-- | @'sepBy1' p sep@ parses /one/ or more occurrences of @p@, separated by
+-- @sep@. Returns a list of values returned by @p@.
+
+sepBy1 :: MonadPlus m => m a -> m sep -> m [a]
+sepBy1 p sep = do
+  x <- p
+  liftM (x:) (many (sep >> p))
+{-# INLINE sepBy1 #-}
+
+-- | @'sepEndBy' p sep@ parses /zero/ or more occurrences of @p@, separated
+-- and optionally ended by @sep@. Returns a list of values returned by @p@.
+
+sepEndBy :: MonadPlus m => m a -> m sep -> m [a]
+sepEndBy p sep = liftM ($ []) (go id)
+  where
+    go f = do
+      r <- optional p
+      case r of
+        Nothing -> return f
+        Just  x -> do
+          more <- option False (re True sep)
+          if more
+            then go (f . (x:))
+            else return (f . (x:))
+{-# INLINE sepEndBy #-}
+
+-- | @'sepEndBy1' p sep@ parses /one/ or more occurrences of @p@, separated
+-- and optionally ended by @sep@. Returns a list of values returned by @p@.
+
+sepEndBy1 :: MonadPlus m => m a -> m sep -> m [a]
+sepEndBy1 p sep = do
+  x <- p
+  more <- option False (re True sep)
+  if more
+    then liftM (x:) (sepEndBy p sep)
+    else return [x]
+{-# INLINE sepEndBy1 #-}
+
+-- | @'skipMany' p@ applies the parser @p@ /zero/ or more times, skipping
+-- its result.
+--
+-- See also: 'manyTill', 'skipManyTill'.
+
+skipMany :: MonadPlus m => m a -> m ()
+skipMany p = go
+  where
+    go = do
+      more <- option False (re True p)
+      when more go
+{-# INLINE skipMany #-}
+
+-- | @'skipSome' p@ applies the parser @p@ /one/ or more times, skipping its
+-- result.
+--
+-- See also: 'someTill', 'skipSomeTill'.
+
+skipSome :: MonadPlus m => m a -> m ()
+skipSome p = p >> skipMany p
+{-# INLINE skipSome #-}
+
+-- | @'skipCount' n p@ parses @n@ occurrences of @p@, skipping its result.
+-- If @n@ is smaller or equal to zero, the parser equals to @'return' []@.
+-- Returns a list of @n@ values.
+--
+-- See also: 'count', 'count''.
+
+skipCount :: Monad m => Int -> m a -> m ()
+skipCount n' p = go n'
+  where
+    go !n =
+      unless (n <= 0) $
+        p >> go (n - 1)
+{-# INLINE skipCount #-}
+
+-- | @'skipManyTill' p end@ applies the parser @p@ /zero/ or more times
+-- skipping results until parser @end@ succeeds. Result parsed by @end@ is
+-- then returned.
+--
+-- See also: 'manyTill', 'skipMany'.
+
+skipManyTill :: MonadPlus m => m a -> m end -> m end
+skipManyTill p end = go
+  where
+    go = do
+      r <- optional end
+      case r of
+        Nothing -> p >> go
+        Just  x -> return x
+{-# INLINE skipManyTill #-}
+
+-- | @'skipSomeTill' p end@ applies the parser @p@ /one/ or more times
+-- skipping results until parser @end@ succeeds. Result parsed by @end@ is
+-- then returned.
+--
+-- See also: 'someTill', 'skipSome'.
+
+skipSomeTill :: MonadPlus m => m a -> m end -> m end
+skipSomeTill p end = p >> skipManyTill p end
+{-# INLINE skipSomeTill #-}
+
+----------------------------------------------------------------------------
+-- Compat helpers (for older GHCs)
+
+re :: Monad m => a -> m b -> m a
+re x = liftM (const x)
+{-# INLINE re #-}
+
+option :: MonadPlus m => a -> m a -> m a
+option x p = p `mplus` return x
+{-# INLINE option #-}
+
+optional :: MonadPlus m => m a -> m (Maybe a)
+optional p = liftM Just p `mplus` return Nothing
+{-# INLINE optional #-}
diff --git a/Control/Monad/Combinators/NonEmpty.hs b/Control/Monad/Combinators/NonEmpty.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Combinators/NonEmpty.hs
@@ -0,0 +1,66 @@
+-- |
+-- Module      :  Control.Monad.Combinators.NonEmpty
+-- Copyright   :  © 2017 Mark Karpov
+-- License     :  BSD 3 clause
+--
+-- Maintainer  :  Mark Karpov <markkarpov92@gmail.com>
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- The module provides 'NonEmpty' list variants of some of the functions
+-- from "Control.Monad.Combinators".
+--
+-- @since 0.4.0
+
+module Control.Monad.Combinators.NonEmpty
+  ( some
+  , endBy1
+  , someTill
+  , sepBy1
+  , sepEndBy1 )
+where
+
+import Control.Monad
+import Data.List.NonEmpty (NonEmpty (..))
+import qualified Control.Monad.Combinators as C
+import qualified Data.List.NonEmpty        as NE
+
+-- | @'some' p@ applies the parser @p@ /one/ or more times and returns a
+-- list of the values returned by @p@.
+--
+-- > word = some letter
+
+some :: MonadPlus m => m a -> m (NonEmpty a)
+some p = liftM NE.fromList (C.some p)
+{-# INLINE some #-}
+
+-- | @'endBy1' p sep@ parses /one/ or more occurrences of @p@, separated and
+-- ended by @sep@. Returns a non-empty list of values returned by @p@.
+
+endBy1 :: MonadPlus m => m a -> m sep -> m (NonEmpty a)
+endBy1 p sep = liftM NE.fromList (C.endBy1 p sep)
+{-# INLINE endBy1 #-}
+
+-- | @'someTill' p end@ works similarly to @'C.manyTill' p end@, but @p@
+-- should succeed at least once.
+--
+-- See also: 'C.skipSome', 'C.skipSomeTill'.
+
+someTill :: MonadPlus m => m a -> m end -> m (NonEmpty a)
+someTill p end = liftM NE.fromList (C.someTill p end)
+{-# INLINE someTill #-}
+
+-- | @'sepBy1' p sep@ parses /one/ or more occurrences of @p@, separated by
+-- @sep@. Returns a non-empty list of values returned by @p@.
+
+sepBy1 :: MonadPlus m => m a -> m sep -> m (NonEmpty a)
+sepBy1 p sep = liftM NE.fromList (C.sepBy1 p sep)
+{-# INLINE sepBy1 #-}
+
+-- | @'sepEndBy1' p sep@ parses /one/ or more occurrences of @p@, separated
+-- and optionally ended by @sep@. Returns a non-empty list of values returned by
+-- @p@.
+
+sepEndBy1 :: MonadPlus m => m a -> m sep -> m (NonEmpty a)
+sepEndBy1 p sep = liftM NE.fromList (C.sepEndBy1 p sep)
+{-# INLINE sepEndBy1 #-}
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -7,8 +7,10 @@
 [![Build Status](https://travis-ci.org/mrkkrp/parser-combinators.svg?branch=master)](https://travis-ci.org/mrkkrp/parser-combinators)
 
 The package provides common parser combinators defined in terms of
-`Applicative` and `Alternative` without any dependencies but `base`. Test
-suite and benchmarks can be found in the [Megaparsec repo](https://github.com/mrkkrp/megaparsec).
+`Applicative` and `Alternative` without any dependencies but `base`. There
+are also more efficient versions of the combinators defined in terms of
+`Monad` and `MonadPlus`. Test suite and benchmarks can be found in the
+[Megaparsec repo](https://github.com/mrkkrp/megaparsec).
 
 ## Contribution
 
diff --git a/parser-combinators.cabal b/parser-combinators.cabal
--- a/parser-combinators.cabal
+++ b/parser-combinators.cabal
@@ -1,5 +1,5 @@
 name:                 parser-combinators
-version:              0.3.0
+version:              0.4.0
 cabal-version:        >= 1.18
 tested-with:          GHC==7.4.2, GHC==7.6.3, GHC==7.8.4, GHC==7.10.3, GHC==8.0.2, GHC==8.2.2
 license:              BSD3
@@ -33,6 +33,8 @@
   exposed-modules:    Control.Applicative.Combinators
                     , Control.Applicative.Combinators.NonEmpty
                     , Control.Applicative.Permutations
+                    , Control.Monad.Combinators
+                    , Control.Monad.Combinators.NonEmpty
   if flag(dev)
     ghc-options:      -Wall -Werror
   else
