diff --git a/parsers.cabal b/parsers.cabal
--- a/parsers.cabal
+++ b/parsers.cabal
@@ -1,6 +1,6 @@
 name:          parsers
 category:      Text, Parsing
-version:       0.11.0.3
+version:       0.12
 license:       BSD3
 cabal-version: >= 1.10
 license-file:  LICENSE
@@ -63,10 +63,30 @@
   default-language: Haskell2010
   build-depends:
     base,
+    bytestring,
     containers,
     directory >= 1.0,
     doctest >= 0.9.1,
-    filepath
+    filepath,
+    QuickCheck,
+    quickcheck-instances
+  ghc-options: -Wall -threaded
+  if impl(ghc<7.6.1)
+    ghc-options: -Werror
+  hs-source-dirs: tests
+
+test-suite quickcheck
+  type:    exitcode-stdio-1.0
+  main-is: QuickCheck.hs
+  default-language: Haskell2010
+  build-depends:
+    attoparsec,
+    base == 4.*,
+    bytestring,
+    parsec >= 3,
+    parsers,
+    QuickCheck,
+    quickcheck-instances
   ghc-options: -Wall -threaded
   if impl(ghc<7.6.1)
     ghc-options: -Werror
diff --git a/src/Text/Parser/Char.hs b/src/Text/Parser/Char.hs
--- a/src/Text/Parser/Char.hs
+++ b/src/Text/Parser/Char.hs
@@ -223,7 +223,7 @@
   text t = t <$ string (unpack t)
   {-# INLINE text #-}
 
-instance (CharParsing m, MonadPlus m) => CharParsing (Lazy.StateT s m) where
+instance (CharParsing m, MonadPlus m, Show s) => CharParsing (Lazy.StateT s m) where
   satisfy = lift . satisfy
   {-# INLINE satisfy #-}
   char    = lift . char
@@ -237,7 +237,7 @@
   text = lift . text
   {-# INLINE text #-}
 
-instance (CharParsing m, MonadPlus m) => CharParsing (Strict.StateT s m) where
+instance (CharParsing m, MonadPlus m, Show s) => CharParsing (Strict.StateT s m) where
   satisfy = lift . satisfy
   {-# INLINE satisfy #-}
   char    = lift . char
@@ -265,7 +265,7 @@
   text = lift . text
   {-# INLINE text #-}
 
-instance (CharParsing m, MonadPlus m, Monoid w) => CharParsing (Strict.WriterT w m) where
+instance (CharParsing m, MonadPlus m, Monoid w, Show w) => CharParsing (Strict.WriterT w m) where
   satisfy = lift . satisfy
   {-# INLINE satisfy #-}
   char    = lift . char
@@ -279,7 +279,7 @@
   text = lift . text
   {-# INLINE text #-}
 
-instance (CharParsing m, MonadPlus m, Monoid w) => CharParsing (Lazy.WriterT w m) where
+instance (CharParsing m, MonadPlus m, Monoid w, Show w) => CharParsing (Lazy.WriterT w m) where
   satisfy = lift . satisfy
   {-# INLINE satisfy #-}
   char    = lift . char
@@ -293,7 +293,7 @@
   text = lift . text
   {-# INLINE text #-}
 
-instance (CharParsing m, MonadPlus m, Monoid w) => CharParsing (Lazy.RWST r w s m) where
+instance (CharParsing m, MonadPlus m, Monoid w, Show w, Show s) => CharParsing (Lazy.RWST r w s m) where
   satisfy = lift . satisfy
   {-# INLINE satisfy #-}
   char    = lift . char
@@ -307,7 +307,7 @@
   text = lift . text
   {-# INLINE text #-}
 
-instance (CharParsing m, MonadPlus m, Monoid w) => CharParsing (Strict.RWST r w s m) where
+instance (CharParsing m, MonadPlus m, Monoid w, Show w, Show s) => CharParsing (Strict.RWST r w s m) where
   satisfy = lift . satisfy
   {-# INLINE satisfy #-}
   char    = lift . char
diff --git a/src/Text/Parser/Combinators.hs b/src/Text/Parser/Combinators.hs
--- a/src/Text/Parser/Combinators.hs
+++ b/src/Text/Parser/Combinators.hs
@@ -276,11 +276,9 @@
   -- behaviour as follows:
   --
   -- >  keywordLet  = try $ string "let" <* notFollowedBy alphaNum
-  notFollowedBy :: (Monad m, Show a) => m a -> m ()
-  notFollowedBy p = try ((try p >>= unexpected . show) <|> pure ())
-  {-# INLINE notFollowedBy #-}
+  notFollowedBy :: Show a => m a -> m ()
 
-instance (Parsing m, MonadPlus m) => Parsing (Lazy.StateT s m) where
+instance (Parsing m, MonadPlus m, Show s) => Parsing (Lazy.StateT s m) where
   try (Lazy.StateT m) = Lazy.StateT $ try . m
   {-# INLINE try #-}
   Lazy.StateT m <?> l = Lazy.StateT $ \s -> m s <?> l
@@ -289,8 +287,11 @@
   {-# INLINE unexpected #-}
   eof = lift eof
   {-# INLINE eof #-}
+  notFollowedBy (Lazy.StateT m) = Lazy.StateT
+    $ \s -> notFollowedBy (m s) >> return ((),s)
+  {-# INLINE notFollowedBy #-}
 
-instance (Parsing m, MonadPlus m) => Parsing (Strict.StateT s m) where
+instance (Parsing m, MonadPlus m, Show s) => Parsing (Strict.StateT s m) where
   try (Strict.StateT m) = Strict.StateT $ try . m
   {-# INLINE try #-}
   Strict.StateT m <?> l = Strict.StateT $ \s -> m s <?> l
@@ -299,6 +300,9 @@
   {-# INLINE unexpected #-}
   eof = lift eof
   {-# INLINE eof #-}
+  notFollowedBy (Strict.StateT m) = Strict.StateT
+    $ \s -> notFollowedBy (m s) >> return ((),s)
+  {-# INLINE notFollowedBy #-}
 
 instance (Parsing m, MonadPlus m) => Parsing (ReaderT e m) where
   try (ReaderT m) = ReaderT $ try . m
@@ -311,8 +315,10 @@
   {-# INLINE unexpected #-}
   eof = lift eof
   {-# INLINE eof #-}
+  notFollowedBy (ReaderT m) = ReaderT $ notFollowedBy . m
+  {-# INLINE notFollowedBy #-}
 
-instance (Parsing m, MonadPlus m, Monoid w) => Parsing (Strict.WriterT w m) where
+instance (Parsing m, MonadPlus m, Monoid w, Show w) => Parsing (Strict.WriterT w m) where
   try (Strict.WriterT m) = Strict.WriterT $ try m
   {-# INLINE try #-}
   Strict.WriterT m <?> l = Strict.WriterT (m <?> l)
@@ -321,8 +327,11 @@
   {-# INLINE unexpected #-}
   eof = lift eof
   {-# INLINE eof #-}
+  notFollowedBy (Strict.WriterT m) = Strict.WriterT
+    $ notFollowedBy m >>= \x -> return (x, mempty)
+  {-# INLINE notFollowedBy #-}
 
-instance (Parsing m, MonadPlus m, Monoid w) => Parsing (Lazy.WriterT w m) where
+instance (Parsing m, MonadPlus m, Monoid w, Show w) => Parsing (Lazy.WriterT w m) where
   try (Lazy.WriterT m) = Lazy.WriterT $ try m
   {-# INLINE try #-}
   Lazy.WriterT m <?> l = Lazy.WriterT (m <?> l)
@@ -331,8 +340,11 @@
   {-# INLINE unexpected #-}
   eof = lift eof
   {-# INLINE eof #-}
+  notFollowedBy (Lazy.WriterT m) = Lazy.WriterT
+    $ notFollowedBy m >>= \x -> return (x, mempty)
+  {-# INLINE notFollowedBy #-}
 
-instance (Parsing m, MonadPlus m, Monoid w) => Parsing (Lazy.RWST r w s m) where
+instance (Parsing m, MonadPlus m, Monoid w, Show w, Show s) => Parsing (Lazy.RWST r w s m) where
   try (Lazy.RWST m) = Lazy.RWST $ \r s -> try (m r s)
   {-# INLINE try #-}
   Lazy.RWST m <?> l = Lazy.RWST $ \r s -> m r s <?> l
@@ -341,8 +353,11 @@
   {-# INLINE unexpected #-}
   eof = lift eof
   {-# INLINE eof #-}
+  notFollowedBy (Lazy.RWST m) = Lazy.RWST
+    $ \r s -> notFollowedBy (m r s) >>= \x -> return (x, s, mempty)
+  {-# INLINE notFollowedBy #-}
 
-instance (Parsing m, MonadPlus m, Monoid w) => Parsing (Strict.RWST r w s m) where
+instance (Parsing m, MonadPlus m, Monoid w, Show w, Show s) => Parsing (Strict.RWST r w s m) where
   try (Strict.RWST m) = Strict.RWST $ \r s -> try (m r s)
   {-# INLINE try #-}
   Strict.RWST m <?> l = Strict.RWST $ \r s -> m r s <?> l
@@ -351,6 +366,9 @@
   {-# INLINE unexpected #-}
   eof = lift eof
   {-# INLINE eof #-}
+  notFollowedBy (Strict.RWST m) = Strict.RWST
+    $ \r s -> notFollowedBy (m r s) >>= \x -> return (x, s, mempty)
+  {-# INLINE notFollowedBy #-}
 
 instance (Parsing m, Monad m) => Parsing (IdentityT m) where
   try = IdentityT . try . runIdentityT
@@ -363,6 +381,8 @@
   {-# INLINE unexpected #-}
   eof = lift eof
   {-# INLINE eof #-}
+  notFollowedBy (IdentityT m) = IdentityT $ notFollowedBy m
+  {-# INLINE notFollowedBy #-}
 
 instance (Parsec.Stream s m t, Show t) => Parsing (Parsec.ParsecT s u m) where
   try           = Parsec.try
@@ -380,6 +400,7 @@
   skipSome        = Att.skipMany1
   unexpected      = fail
   eof             = Att.endOfInput
+  notFollowedBy p = optional p >>= maybe (pure ()) (unexpected . show)
 
 instance Parsing ReadP.ReadP where
   try        = id
@@ -388,6 +409,8 @@
   skipSome   = ReadP.skipMany1
   unexpected = const ReadP.pfail
   eof        = ReadP.eof
+  notFollowedBy p = ((Just <$> p) ReadP.<++ pure Nothing)
+    >>= maybe (pure ()) (unexpected . show)
 
 #ifdef ORPHAN_ALTERNATIVE_READP
 instance Applicative ReadP.ReadP where
@@ -398,3 +421,4 @@
   empty = mzero
   (<|>) = mplus
 #endif
+
diff --git a/src/Text/Parser/LookAhead.hs b/src/Text/Parser/LookAhead.hs
--- a/src/Text/Parser/LookAhead.hs
+++ b/src/Text/Parser/LookAhead.hs
@@ -46,11 +46,11 @@
   -- | @lookAhead p@ parses @p@ without consuming any input.
   lookAhead :: m a -> m a
 
-instance (LookAheadParsing m, MonadPlus m) => LookAheadParsing (Lazy.StateT s m) where
+instance (LookAheadParsing m, MonadPlus m, Show s) => LookAheadParsing (Lazy.StateT s m) where
   lookAhead (Lazy.StateT m) = Lazy.StateT $ lookAhead . m
   {-# INLINE lookAhead #-}
 
-instance (LookAheadParsing m, MonadPlus m) => LookAheadParsing (Strict.StateT s m) where
+instance (LookAheadParsing m, MonadPlus m, Show s) => LookAheadParsing (Strict.StateT s m) where
   lookAhead (Strict.StateT m) = Strict.StateT $ lookAhead . m
   {-# INLINE lookAhead #-}
 
@@ -58,19 +58,19 @@
   lookAhead (ReaderT m) = ReaderT $ lookAhead . m
   {-# INLINE lookAhead #-}
 
-instance (LookAheadParsing m, MonadPlus m, Monoid w) => LookAheadParsing (Strict.WriterT w m) where
+instance (LookAheadParsing m, MonadPlus m, Monoid w, Show w) => LookAheadParsing (Strict.WriterT w m) where
   lookAhead (Strict.WriterT m) = Strict.WriterT $ lookAhead m
   {-# INLINE lookAhead #-}
 
-instance (LookAheadParsing m, MonadPlus m, Monoid w) => LookAheadParsing (Lazy.WriterT w m) where
+instance (LookAheadParsing m, MonadPlus m, Monoid w, Show w) => LookAheadParsing (Lazy.WriterT w m) where
   lookAhead (Lazy.WriterT m) = Lazy.WriterT $ lookAhead m
   {-# INLINE lookAhead #-}
 
-instance (LookAheadParsing m, MonadPlus m, Monoid w) => LookAheadParsing (Lazy.RWST r w s m) where
+instance (LookAheadParsing m, MonadPlus m, Monoid w, Show w, Show s) => LookAheadParsing (Lazy.RWST r w s m) where
   lookAhead (Lazy.RWST m) = Lazy.RWST $ \r s -> lookAhead (m r s)
   {-# INLINE lookAhead #-}
 
-instance (LookAheadParsing m, MonadPlus m, Monoid w) => LookAheadParsing (Strict.RWST r w s m) where
+instance (LookAheadParsing m, MonadPlus m, Monoid w, Show w, Show s) => LookAheadParsing (Strict.RWST r w s m) where
   lookAhead (Strict.RWST m) = Strict.RWST $ \r s -> lookAhead (m r s)
   {-# INLINE lookAhead #-}
 
diff --git a/src/Text/Parser/Token.hs b/src/Text/Parser/Token.hs
--- a/src/Text/Parser/Token.hs
+++ b/src/Text/Parser/Token.hs
@@ -344,7 +344,7 @@
   token :: m a -> m a
   token p = p <* (someSpace <|> pure ())
 
-instance (TokenParsing m, MonadPlus m) => TokenParsing (Lazy.StateT s m) where
+instance (TokenParsing m, MonadPlus m, Show s) => TokenParsing (Lazy.StateT s m) where
   nesting (Lazy.StateT m) = Lazy.StateT $ nesting . m
   {-# INLINE nesting #-}
   someSpace = lift someSpace
@@ -354,7 +354,7 @@
   highlight h (Lazy.StateT m) = Lazy.StateT $ highlight h . m
   {-# INLINE highlight #-}
 
-instance (TokenParsing m, MonadPlus m) => TokenParsing (Strict.StateT s m) where
+instance (TokenParsing m, MonadPlus m, Show s) => TokenParsing (Strict.StateT s m) where
   nesting (Strict.StateT m) = Strict.StateT $ nesting . m
   {-# INLINE nesting #-}
   someSpace = lift someSpace
@@ -374,7 +374,7 @@
   highlight h (ReaderT m) = ReaderT $ highlight h . m
   {-# INLINE highlight #-}
 
-instance (TokenParsing m, MonadPlus m, Monoid w) => TokenParsing (Strict.WriterT w m) where
+instance (TokenParsing m, MonadPlus m, Monoid w, Show w) => TokenParsing (Strict.WriterT w m) where
   nesting (Strict.WriterT m) = Strict.WriterT $ nesting m
   {-# INLINE nesting #-}
   someSpace = lift someSpace
@@ -384,7 +384,7 @@
   highlight h (Strict.WriterT m) = Strict.WriterT $ highlight h m
   {-# INLINE highlight #-}
 
-instance (TokenParsing m, MonadPlus m, Monoid w) => TokenParsing (Lazy.WriterT w m) where
+instance (TokenParsing m, MonadPlus m, Monoid w, Show w) => TokenParsing (Lazy.WriterT w m) where
   nesting (Lazy.WriterT m) = Lazy.WriterT $ nesting m
   {-# INLINE nesting #-}
   someSpace = lift someSpace
@@ -394,7 +394,7 @@
   highlight h (Lazy.WriterT m) = Lazy.WriterT $ highlight h m
   {-# INLINE highlight #-}
 
-instance (TokenParsing m, MonadPlus m, Monoid w) => TokenParsing (Lazy.RWST r w s m) where
+instance (TokenParsing m, MonadPlus m, Monoid w, Show w, Show s) => TokenParsing (Lazy.RWST r w s m) where
   nesting (Lazy.RWST m) = Lazy.RWST $ \r s -> nesting (m r s)
   {-# INLINE nesting #-}
   someSpace = lift someSpace
@@ -404,7 +404,7 @@
   highlight h (Lazy.RWST m) = Lazy.RWST $ \r s -> highlight h (m r s)
   {-# INLINE highlight #-}
 
-instance (TokenParsing m, MonadPlus m, Monoid w) => TokenParsing (Strict.RWST r w s m) where
+instance (TokenParsing m, MonadPlus m, Monoid w, Show w, Show s) => TokenParsing (Strict.RWST r w s m) where
   nesting (Strict.RWST m) = Strict.RWST $ \r s -> nesting (m r s)
   {-# INLINE nesting #-}
   someSpace = lift someSpace
@@ -683,7 +683,10 @@
   {-# INLINE unexpected #-}
   eof = Unhighlighted eof
   {-# INLINE eof #-}
+  notFollowedBy (Unhighlighted m) = Unhighlighted $ notFollowedBy m
+  {-# INLINE notFollowedBy #-}
 
+
 instance MonadTrans Unhighlighted where
   lift = Unhighlighted
   {-# INLINE lift #-}
@@ -712,6 +715,8 @@
   {-# INLINE unexpected #-}
   eof = Unspaced eof
   {-# INLINE eof #-}
+  notFollowedBy (Unspaced m) = Unspaced $ notFollowedBy m
+  {-# INLINE notFollowedBy #-}
 
 instance MonadTrans Unspaced where
   lift = Unspaced
@@ -741,6 +746,8 @@
   {-# INLINE unexpected #-}
   eof = Unlined eof
   {-# INLINE eof #-}
+  notFollowedBy (Unlined m) = Unlined $ notFollowedBy m
+  {-# INLINE notFollowedBy #-}
 
 instance MonadTrans Unlined where
   lift = Unlined
diff --git a/tests/QuickCheck.hs b/tests/QuickCheck.hs
new file mode 100644
--- /dev/null
+++ b/tests/QuickCheck.hs
@@ -0,0 +1,94 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE CPP #-}
+
+module Main
+( main
+) where
+
+import Control.Applicative
+
+import Data.Attoparsec.ByteString.Char8 (parseOnly)
+import qualified Data.ByteString.Char8 as B8
+
+#if MIN_VERSION_base(4,7,0)
+import Data.Either
+#endif
+
+import Test.QuickCheck
+import Test.QuickCheck.Instances ()
+
+import Text.Parsec.Prim as P (parse)
+import Text.Parser.Char
+import Text.Parser.Combinators
+import Text.ParserCombinators.ReadP (readP_to_S)
+
+-- -------------------------------------------------------------------------- --
+-- Run tests with different parser frameworks
+
+-- Instead of letting quick check pick the parser framework as a test parameter
+-- it may be better to just run all tests for each parser framework.
+
+data P a = P ((Monad m, CharParsing m) => m a)
+
+data TestParser a = TestParser String (P a -> String -> Either String a)
+
+instance Show (TestParser a) where show (TestParser n _) = n
+
+pAtto, pParsec, pReadP :: TestParser a
+pAtto = TestParser "attoparsec" $ \(P p) -> parseOnly p . B8.pack
+pParsec = TestParser "parsec" $ \(P p) -> either (Left . show) Right . parse p "test input"
+pReadP = TestParser "ReadP" $ \(P p) s -> case readP_to_S p s of
+  [] -> Left "parseFailed"
+  (a,_):_ -> Right a
+
+instance Arbitrary (TestParser a) where
+    arbitrary = elements [pReadP, pAtto, pParsec]
+
+-- -------------------------------------------------------------------------- --
+-- Main
+
+main :: IO ()
+main = mapM_ quickCheck tests
+
+-- -------------------------------------------------------------------------- --
+-- Tests
+
+tests :: [Property]
+tests =
+    [ property prop_notFollowedBy0
+    , property prop_notFollowedBy1
+    , property prop_notFollowedBy2
+    , property prop_notFollowedBy3
+    ]
+
+-- -------------------------------------------------------------------------- --
+-- Properties
+
+prop_notFollowedBy0 :: TestParser Char -> Char -> Char -> Bool
+prop_notFollowedBy0 (TestParser _ p) x y = either (\_ -> x == y) (/= y)
+    $ p (P (notFollowedBy (char y) *> anyChar)) [x]
+
+prop_notFollowedBy1 :: TestParser Char -> Char -> Bool
+prop_notFollowedBy1 (TestParser _ p) x = either (\_ -> x == x) (/= x)
+    $ p (P (notFollowedBy (char x) *> anyChar)) [x]
+
+prop_notFollowedBy2 :: TestParser Char -> String -> Char -> Bool
+prop_notFollowedBy2 (TestParser _ p) x y = isLeft
+    $ p (P (anyChar *> notFollowedBy (char y) *> char y)) x
+
+prop_notFollowedBy3 :: TestParser () -> Char -> Bool
+prop_notFollowedBy3 (TestParser _ p) x = isRight
+    $ p (P (notFollowedBy (char x) <|> char x *> pure ())) [x]
+
+-- -------------------------------------------------------------------------- --
+-- Utils
+
+#if !MIN_VERSION_base(4,7,0)
+isLeft :: Either a b -> Bool
+isLeft = either (const True) (const False)
+
+isRight :: Either a b -> Bool
+isRight = either (const False) (const True)
+#endif
