diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
 # Revision history for bytesmith
 
+## 0.3.2.0 -- 2019-??-??
+
+* Add `parseBytesEither` and `parseBytesMaybe`.
+* Add common idioms from other parser libaries. This includes: `satisfy`,
+  `satisfyWith`, `scan`, `peek`, and `peek'`.
+
 ## 0.3.1.0 -- 2019-11-12
 
 * Add big-endian and little-endian parsers for `Word128`.
diff --git a/bytesmith.cabal b/bytesmith.cabal
--- a/bytesmith.cabal
+++ b/bytesmith.cabal
@@ -1,6 +1,6 @@
 cabal-version: 2.2
 name: bytesmith
-version: 0.3.1.0
+version: 0.3.2.0
 synopsis: Nonresumable byte parser
 description:
   Parse bytes as fast as possible. This is a nonresumable parser
@@ -31,7 +31,7 @@
   build-depends:
     , base >=4.12 && <5
     , bytestring >=0.10.8 && <0.11
-    , byteslice >=0.1.3 && <0.2
+    , byteslice >=0.1.3 && <0.3
     , contiguous >= 0.4 && < 0.6
     , primitive >=0.7 && <0.8
     , text-short >=0.1.3 && <0.2
diff --git a/src/Data/Bytes/Parser.hs b/src/Data/Bytes/Parser.hs
--- a/src/Data/Bytes/Parser.hs
+++ b/src/Data/Bytes/Parser.hs
@@ -26,9 +26,12 @@
   , Result(..)
   , Slice(..)
     -- * Run Parsers
+    -- ** Result
   , parseByteArray
   , parseBytes
   , parseBytesEffectfully
+  , parseBytesEither
+  , parseBytesMaybe
     -- * One Byte
   , any
     -- * Many Bytes
@@ -41,10 +44,17 @@
     -- * Match
   , byteArray
   , bytes
+  , satisfy
+  , satisfyWith
     -- * End of Input
   , endOfInput
   , isEndOfInput
   , remaining
+    -- * Scanning
+  , scan
+    -- * Lookahead
+  , peek
+  , peek'
     -- * Control Flow
   , fail
   , orElse
@@ -99,7 +109,7 @@
 import qualified Data.Primitive as PM
 import qualified Data.Primitive.Contiguous as C
 
--- | Parse a slice of a byte array. This can succeed even if the
+-- | Parse a byte sequence. This can succeed even if the
 -- entire slice was not consumed by the parser.
 parseBytes :: forall e a. (forall s. Parser e s a) -> Bytes -> Result e a
 parseBytes p !b = runResultST action
@@ -108,6 +118,38 @@
   action s0 = case p @s of
     Parser f -> f (unboxBytes b) s0
 
+-- | Variant of 'parseBytesEither' that discards the error message on failure.
+-- Just like 'parseBytesEither', this does not impose any checks on the length
+-- of the remaining input.
+parseBytesMaybe :: forall e a. (forall s. Parser e s a) -> Bytes -> Maybe a
+parseBytesMaybe p !b = runMaybeST action
+  where
+  action :: forall s. ST# s (Result# e a)
+  action s0 = case p @s of
+    Parser f -> f (unboxBytes b) s0
+
+-- | Variant of 'parseBytes' that discards the new offset and the
+-- remaining length. This does not, however, require the remaining
+-- length to be zero. Use 'endOfInput' to accomplish that.
+parseBytesEither :: forall e a. (forall s. Parser e s a) -> Bytes -> Either e a
+parseBytesEither p !b = runEitherST action
+  where
+  action :: forall s. ST# s (Result# e a)
+  action s0 = case p @s of
+    Parser f -> f (unboxBytes b) s0
+
+-- Similar to runResultST
+runMaybeST :: (forall s. ST# s (Result# e x)) -> Maybe x
+runMaybeST f = case (runRW# (\s0 -> case f s0 of { (# _, r #) -> r })) of
+  (# _ | #) -> Nothing
+  (# | (# x, _, _ #) #) -> Just x
+
+-- Similar to runResultST
+runEitherST :: (forall s. ST# s (Result# e x)) -> Either e x
+runEitherST f = case (runRW# (\s0 -> case f s0 of { (# _, r #) -> r })) of
+  (# e | #) -> Left e
+  (# | (# x, _, _ #) #) -> Right x
+
 -- This is used internally to help reduce boxing when a parser
 -- gets run. Due to the late inlining of runRW#, this variant
 -- of runST still cause the result value to be boxed. However,
@@ -172,6 +214,49 @@
      in InternalSuccess w (offset chunk + 1) (length chunk - 1)
   else InternalFailure e
 
+-- | Match any byte, to perform lookahead. Returns 'Nothing' if
+--   end of input has been reached. Does not consume any input.
+--
+--   /Note/: Because this parser does not fail, do not use it
+--   with combinators such as 'many', because such as 'many',
+--   because such parsers loop until a failure occurs. Careless
+--   use will thus result in an infinite loop.
+peek :: Parser e s (Maybe Word8)
+peek = uneffectful $ \chunk ->
+  let v = if length chunk > 0
+        then Just (B.unsafeIndex chunk 1)
+        else Nothing
+  in InternalSuccess v (offset chunk) (length chunk)
+
+-- | Match any byte, to perform lookahead. Does not consume any
+--   input, but will fail if end of input has been reached.
+peek' :: e -> Parser e s Word8
+peek' e = uneffectful $ \chunk -> if length chunk > 0
+  then InternalSuccess (B.unsafeIndex chunk 1) (offset chunk) (length chunk)
+  else InternalFailure e
+
+-- | A stateful scanner. The predicate consumes and transforms a
+--   state argument, and each transformed state is passed to
+--   successive invocations of the predicate on each byte of the input
+--   until one returns 'Nothing' or the input ends.
+--
+--   This parser does not fail. It will return the initial state
+--   if the predicate returns 'Nothing' on the first byte of input.
+--
+--   /Note/: Because this parser does not fail, do not use it with
+--   combinators such a 'many', because such parsers loop until a
+--   failure occurs. Careless use will thus result in an infinite loop.
+scan :: state -> (state -> Word8 -> Maybe state) -> Parser e s state
+scan s0 t = do
+  let go s = do
+        mw <- peek
+        case mw of
+          Nothing -> pure s
+          Just w -> case t s w of
+            Just s' -> go s'
+            Nothing -> pure s
+  go s0
+
 -- Interpret the next byte as an ASCII-encoded character.
 -- Does not check to see if any characters are left. This
 -- is not exported.
@@ -246,6 +331,25 @@
         then go
         else unconsume 1
 
+-- | The parser @satisfy p@ succeeds for any byte for which the
+--   predicate @p@ returns 'True'. Returns the byte that is
+--   actually parsed.
+satisfy :: e -> (Word8 -> Bool) -> Parser e s Word8
+satisfy e p = satisfyWith e id p
+{-# inline satisfy #-}
+
+-- | The parser @satisfyWith f p@ transforms a byte, and succeeds
+--   if the predicate @p@ returns 'True' on the transformed value.
+--   The parser returns the transformed byte that was parsed.
+satisfyWith :: e -> (Word8 -> a) -> (a -> Bool) -> Parser e s a
+satisfyWith e f p = uneffectful $ \chunk -> if length chunk > 1
+  then case B.unsafeIndex chunk 1 of
+    w ->
+      let v = f w
+      in if p v
+        then InternalSuccess v (offset chunk + 1) (length chunk - 1)
+        else InternalFailure e
+  else InternalFailure e
 
 -- | Fails if there is still more input remaining.
 endOfInput :: e -> Parser e s ()
