diff --git a/bench/bench.hs b/bench/bench.hs
--- a/bench/bench.hs
+++ b/bench/bench.hs
@@ -28,9 +28,7 @@
       intInput = ":123\r\n"
       bulkInput = "$10\r\n0123456789\r\n"
       multiInput = "*3\r\n+A\r\n+B\r\n+C\r\n"
-      binaryInput =
-        let str = ByteString.pack [5, 65, 66, 67, 68, 69]
-        in ByteString.concat (replicate 10 str)
+      binaryInput = ByteString.pack [5, 65, 66, 67, 68, 69]
   print (stringAtto smallStringInput)
   print (stringScanner smallStringInput)
   print (stringWordScanner smallStringInput)
@@ -47,8 +45,6 @@
   print (redisAttoReply multiInput)
   print (redisZeptoReply multiInput)
   print (redisScannerReply multiInput)
-  print (binaryScanner binaryInput)
-  print (binaryCereal binaryInput)
   defaultMain
     [ bgroup "scanner"
       [ bgroup "string"
@@ -160,45 +156,19 @@
     _ -> Left "Unknown type"
   Nothing -> Left "Not enought input"
 
-binaryScanner :: ByteString -> Either String [ByteString]
-binaryScanner bs = case Scanner.scan p' bs of
+binaryScanner :: ByteString -> Either String ByteString
+binaryScanner bs = case Scanner.scan p bs of
   Scanner.Done _ r -> Right r
   Scanner.Fail _ err -> Left err
   Scanner.More _ -> Left "Not enought input"
   where
-  p' = do
-    a0 <- p
-    a1 <- p
-    a2 <- p
-    a3 <- p
-    a4 <- p
-    a5 <- p
-    a6 <- p
-    a7 <- p
-    a8 <- p
-    a9 <- p
-    return [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]
-  {-# INLINE p #-}
   p = do
     n <- fromIntegral <$> Scanner.anyWord8
     Scanner.take n
 
-binaryCereal :: ByteString -> Either String [ByteString]
-binaryCereal bs = Cereal.runGet g' bs
+binaryCereal :: ByteString -> Either String ByteString
+binaryCereal bs = Cereal.runGet g bs
   where
-  g' = do
-    a0 <- g
-    a1 <- g
-    a2 <- g
-    a3 <- g
-    a4 <- g
-    a5 <- g
-    a6 <- g
-    a7 <- g
-    a8 <- g
-    a9 <- g
-    return [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]
-  {-# INLINE g #-}
   g = do
     n <- fromIntegral <$> Cereal.getWord8
     Cereal.getBytes n
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,7 @@
+0.3.1
+
+* support ghc-8.8
+
 0.3
 
 * add foldWhile, foldWhile1, satisfy, satisfyMaybe
diff --git a/lib/Scanner/Internal.hs b/lib/Scanner/Internal.hs
--- a/lib/Scanner/Internal.hs
+++ b/lib/Scanner/Internal.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE RankNTypes, BangPatterns #-}
+{-# LANGUAGE RankNTypes, BangPatterns, CPP #-}
 {-# OPTIONS_HADDOCK not-home #-}
 
 -- | Scanner implementation
@@ -13,6 +13,7 @@
 import qualified Data.ByteString.Unsafe as ByteString (unsafeDrop)
 import qualified Scanner.OctetPredicates as OctetPredicates
 import Control.Monad
+import Control.Monad.Fail
 
 -- | CPS scanner without backtracking
 newtype Scanner a = Scanner
@@ -65,10 +66,17 @@
     run s1 bs $ \bs' a ->
       run (s2 a) bs' next
 
+#if !(MIN_VERSION_base(4,13,0))
   {-# INLINE  fail #-}
   fail err = Scanner $ \bs _ ->
     Fail bs err
+#endif
 
+instance MonadFail Scanner where
+  {-# INLINE  fail #-}
+  fail err = Scanner $ \bs _ ->
+    Fail bs err
+
 -- | Consume the next word
 --
 -- It fails if end of input
@@ -156,7 +164,7 @@
     bs <- take (ByteString.length str)
     if bs == str
       then return ()
-      else fail "Unexpected input"
+      else Control.Monad.Fail.fail "Unexpected input"
 
 -- | Return the next byte, if any, without consuming it
 {-# INLINE lookAhead #-}
diff --git a/scanner.cabal b/scanner.cabal
--- a/scanner.cabal
+++ b/scanner.cabal
@@ -1,5 +1,5 @@
 name:                scanner
-version:             0.3
+version:             0.3.1
 synopsis:            Fast non-backtracking incremental combinator parsing for bytestrings
 homepage:            https://github.com/Yuras/scanner
 license:             BSD3
@@ -25,6 +25,7 @@
                        Data.Either
                        Scanner.OctetPredicates
   build-depends:       base <5
+                     , fail
                      , bytestring
   hs-source-dirs:      lib, compat
   ghc-options:         -O2
