diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## Version 0.1 (unreleased)
+
+- Support Perl-compatible regular expressions (`[-e|--regex]`)
+- Remove redundant dependencies
+
 ## Version 0.0 (2017-10-03)
 
 - Initial release
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -6,16 +6,24 @@
 
 ## Usage
 
-`hgrep` requires an expression and a set of files to search across to
-function. For now, an expression can only be the full name of a type
-or an expression.
-
-```
+```haskell
 $> hgrep
-Usage: hgrep EXPRESSION [FILE]
+Usage: hgrep [-e|--regex] EXPRESSION [FILE]
 ```
 
-```
+`hgrep` requires an expression and a set of files to search across.
+
+An expression can be one of
+- The name of a type, e.g. `FooBar`
+- The name of an expression, e.g. `foo`
+- A regular expression (via the `-e` flag), e.g. `-e Foo$`
+
+Each file will be parsed and searched. Results will be printed to the
+console, with syntax highlighting where possible.
+
+### Searching for top-level expressions
+
+```haskell
 $> hgrep main main/hgrep.hs
 main/hgrep.hs:16:1-13
 
@@ -27,11 +35,33 @@
   putStrLn "Hello, world!"
 ```
 
-```
+### Searching for type declarations
+
+```haskell
 $> hgrep PrintOpts src/**/*.hs
 src/Language/Haskell/HGrep/Internal/Data.hs:(40,1)-(42,28)
 
 data PrintOpts = PrintOpts {
     poColourOpts :: ColourOpts
   } deriving (Eq, Ord, Show)
+```
+
+### Searching with a regular expression
+
+```haskell
+$> hgrep -e 'Opts$' src/**/*.hs
+src/Language/Haskell/HGrep/Internal/Data.hs:(57,1)-(59,28)
+
+data PrintOpts = PrintOpts {
+    poColourOpts :: ColourOpts
+  } deriving (Eq, Ord, Show)
+src/Language/Haskell/HGrep/Internal/Data.hs:(61,1)-(64,26)
+
+defaultPrintOpts :: PrintOpts
+src/Language/Haskell/HGrep/Internal/Data.hs:(67,1)-(70,5)
+
+defaultPrintOpts =
+  PrintOpts {
+      poColourOpts = DefaultColours
+    }
 ```
diff --git a/hgrep.cabal b/hgrep.cabal
--- a/hgrep.cabal
+++ b/hgrep.cabal
@@ -1,5 +1,5 @@
 name:                hgrep
-version:             0.0
+version:             0.1
 homepage:            https://github.com/thumphries/hgrep
 author:              Tim Humphries
 maintainer:          tim@utf8.me
@@ -9,7 +9,7 @@
 category:            Language
 build-type:          Simple
 cabal-version:       >=1.10
-tested-with:         GHC == 8.0.2
+tested-with:         GHC == 8.0.1, GHC == 8.0.2, GHC == 8.2.1
 extra-source-files:
   README.md
   CHANGELOG.md
@@ -36,6 +36,7 @@
                    , ansi-terminal                  >= 0.6.3         && < 0.8
                    , optparse-applicative           >= 0.13          && < 0.15
 
+
 library
   default-language:  Haskell2010
   hs-source-dirs:    src
@@ -43,13 +44,13 @@
   build-depends:
                      base                           >= 4.9           && < 4.11
                    , ansi-terminal                  >= 0.6.3         && < 0.8
+                   , bytestring                     >= 0.10.4        && < 0.12
                    , ghc                            >= 7.10.2        && < 8.3
-                   , ghc-exactprint                 >= 0.5           && < 0.6
+                   , ghc-exactprint                 >= 0.5.4.0       && < 0.6
                    , hscolour                       >= 1.24          && < 1.25
                    , lens                           >= 4.15          && < 4.16
+                   , pcre-heavy                     >= 1.0           && < 1.1
                    , template-haskell               >= 2.11          && < 2.13
-                   , transformers                   >= 0.5           && < 0.7
-                   , transformers-bifunctors        >= 0.1           && < 1.0
 
   exposed-modules:
                      Language.Haskell.HGrep
diff --git a/main/hgrep.hs b/main/hgrep.hs
--- a/main/hgrep.hs
+++ b/main/hgrep.hs
@@ -19,11 +19,16 @@
   IO.hSetBuffering IO.stderr IO.LineBuffering
   opts <- parseOpts
   colour <- detectColour
-  found <-
-    fmap sum $
-      for (cmdFiles opts) $ \fp ->
-        hgrep (HGrep.PrintOpts colour) (cmdQuery opts) fp
-  exitWith (exitCode found)
+  case parseQuery (cmdQuery opts) (cmdRegex opts) of
+    Left er -> do
+      IO.hPutStrLn IO.stderr er
+      exitWith (ExitFailure 2)
+    Right q -> do
+      found <-
+        fmap sum $
+          for (cmdFiles opts) $ \fp ->
+            hgrep (HGrep.PrintOpts colour) q fp
+      exitWith (exitCode found)
 
 exitCode :: Integer -> ExitCode
 exitCode found
@@ -44,8 +49,8 @@
 hgrep popts q fp = do
   esrc <- HGrep.parseModule fp
   case esrc of
-    Left err ->
-      -- FIXME report or count errors
+    Left err -> do
+      IO.hPutStrLn IO.stderr (HGrep.printParseError err)
       pure 0
 
     Right src -> do
@@ -53,10 +58,20 @@
       HGrep.printResults popts results
       pure $ fromIntegral (length results)
 
+
+parseQuery :: [Char] -> Bool -> Either [Char] HGrep.Query
+parseQuery str regex =
+  case regex of
+    True ->
+      HGrep.MatchRegex <$> HGrep.compileRegex str
+    False ->
+      pure $ HGrep.MatchSimple str
+
 -- -----------------------------------------------------------------------------
 
 data CmdOpts = CmdOpts {
     cmdQuery :: [Char]
+  , cmdRegex :: Bool
   , cmdFiles :: [FilePath]
   } deriving (Eq, Ord, Show)
 
@@ -71,4 +86,6 @@
 parser =
   CmdOpts
     <$> O.argument O.str (O.metavar "QUERY")
+    <*> O.switch
+          (O.short 'e' <> O.long "regex" <> O.help "Match a regular expression")
     <*> many (O.argument O.str (O.metavar "FILE"))
diff --git a/src/Language/Haskell/HGrep.hs b/src/Language/Haskell/HGrep.hs
--- a/src/Language/Haskell/HGrep.hs
+++ b/src/Language/Haskell/HGrep.hs
@@ -4,11 +4,17 @@
   -- * Parsing
     ParsedSource
   , parseModule
+  , ParseError
+  , HP.printParseError
   -- * Searching
-  , Query
+  -- ** Queries
+  , Query (..)
+  , Regex
+  , compileRegex
+  -- ** Running queries
   , SearchResult
   , queryModule
-  -- * Printing
+  -- * Printing results
   , PrintOpts (..)
   , defaultPrintOpts
   , ColourOpts (..)
diff --git a/src/Language/Haskell/HGrep/Internal/Data.hs b/src/Language/Haskell/HGrep/Internal/Data.hs
--- a/src/Language/Haskell/HGrep/Internal/Data.hs
+++ b/src/Language/Haskell/HGrep/Internal/Data.hs
@@ -6,7 +6,9 @@
 module Language.Haskell.HGrep.Internal.Data (
     ParsedSource (..)
   , ParseError (..)
-  , Query
+  , Query (..)
+  , Regex (..)
+  , compileRegex
   , SearchResult (..)
   , PrintOpts (..)
   , defaultPrintOpts
@@ -14,11 +16,15 @@
   ) where
 
 
+import qualified Data.ByteString.Char8 as B8
+
 import           Language.Haskell.HGrep.Prelude
 
 import qualified Language.Haskell.GHC.ExactPrint.Annotater as EA
 import qualified Language.Haskell.GHC.ExactPrint.Types as ET
 
+import qualified Text.Regex.PCRE.Heavy as PCRE
+
 import qualified GHC
 import qualified SrcLoc
 
@@ -31,7 +37,18 @@
     unParseError :: (SrcLoc.SrcSpan, [Char])
   }
 
-type Query = [Char]
+data Query =
+    MatchSimple [Char]
+  | MatchRegex Regex
+  deriving (Eq, Ord, Show)
+
+newtype Regex = Regex {
+    unRegex :: PCRE.Regex
+  } deriving (Eq, Ord, Show)
+
+compileRegex :: [Char] -> Either [Char] Regex
+compileRegex str =
+  fmap Regex (PCRE.compileM (B8.pack str) [])
 
 data SearchResult =
   forall ast. EA.Annotate ast =>
diff --git a/src/Language/Haskell/HGrep/Internal/Lens.hs b/src/Language/Haskell/HGrep/Internal/Lens.hs
--- a/src/Language/Haskell/HGrep/Internal/Lens.hs
+++ b/src/Language/Haskell/HGrep/Internal/Lens.hs
@@ -20,7 +20,7 @@
 import           HsExpr
 import           HsLit
 import           HsSyn
-import           OccName
+import           Name
 import           RdrName
 import           SrcLoc
 
@@ -35,6 +35,7 @@
 
 makeOptics ''OccName
 makeOptics ''RdrName
+makeOptics ''Name
 
 makeOptics ''HsModule
 
diff --git a/src/Language/Haskell/HGrep/Prelude.hs b/src/Language/Haskell/HGrep/Prelude.hs
--- a/src/Language/Haskell/HGrep/Prelude.hs
+++ b/src/Language/Haskell/HGrep/Prelude.hs
@@ -51,10 +51,6 @@
   , MonadPlus (..)
   , guard
   , msum
-  -- ** MonadTrans
-  , MonadTrans (..)
-  -- ** BifunctorTrans
-  , BifunctorTrans (..)
   -- ** MonadIO
   , MonadIO (..)
 
@@ -63,20 +59,11 @@
   , Either (..)
   , either
   , note
-  -- *** EitherT
-  , EitherT
-  , pattern EitherT
-  , runEitherT
-  , left
-  , right
   -- ** Maybe
   , Maybe (..)
   , fromMaybe
   , maybe
   , hush
-  -- *** MaybeT
-  , MaybeT (..)
-  , nothing
   -- ** Tuple
   , fst
   , snd
@@ -148,20 +135,6 @@
 import           Control.Monad.IO.Class (
            MonadIO (..)
          )
-import           Control.Monad.Trans.Bifunctor as BifunctorTrans (
-           BifunctorTrans (..)
-         )
-import           Control.Monad.Trans.Class as MonadTrans (
-           MonadTrans (..)
-         )
-import           Control.Monad.Trans.Except as ExceptT (
-           ExceptT (..)
-         , runExceptT
-         , throwE
-         )
-import           Control.Monad.Trans.Maybe as MaybeT (
-           MaybeT (..)
-         )
 import           Control.Applicative as Applicative (
            Applicative (..)
          , (<**>)
@@ -335,27 +308,3 @@
 hush (Left _) = Nothing
 hush (Right b) = Just b
 {-# INLINEABLE hush #-}
-
-type EitherT = ExceptT
-pattern EitherT :: m (Either e a) -> ExceptT e m a
-pattern EitherT m = ExceptT m
-
-runEitherT :: EitherT e m a -> m (Either e a)
-runEitherT =
-  ExceptT.runExceptT
-{-# INLINE runEitherT #-}
-
-left :: Monad m => x -> EitherT x m a
-left =
-  throwE
-{-# INLINE left #-}
-
-right :: Monad m => a -> EitherT x m a
-right =
-  return
-{-# INLINE right #-}
-
-nothing :: Monad m => MaybeT m a
-nothing =
-  MaybeT (return Nothing)
-{-# INLINE nothing #-}
diff --git a/src/Language/Haskell/HGrep/Print.hs b/src/Language/Haskell/HGrep/Print.hs
--- a/src/Language/Haskell/HGrep/Print.hs
+++ b/src/Language/Haskell/HGrep/Print.hs
@@ -1,7 +1,8 @@
 {-# LANGUAGE NoImplicitPrelude #-}
 {-# LANGUAGE OverloadedStrings #-}
 module Language.Haskell.HGrep.Print (
-    printSearchResult
+    printParseError
+  , printSearchResult
   , printSearchResultLocation
   ) where
 
@@ -20,6 +21,13 @@
 import qualified Outputable
 import qualified SrcLoc
 
+
+printParseError :: ParseError -> [Char]
+printParseError (ParseError (loc, msg)) =
+  L.intercalate ": " [
+      unsafePpr loc
+    , msg
+    ]
 
 printSearchResult :: PrintOpts -> SearchResult -> [Char]
 printSearchResult (PrintOpts co) (SearchResult anns ast) =
diff --git a/src/Language/Haskell/HGrep/Query.hs b/src/Language/Haskell/HGrep/Query.hs
--- a/src/Language/Haskell/HGrep/Query.hs
+++ b/src/Language/Haskell/HGrep/Query.hs
@@ -18,6 +18,8 @@
 import           Language.Haskell.HGrep.Internal.Lens
 import           Language.Haskell.HGrep.Prelude
 
+import           Text.Regex.PCRE.Heavy ((=~))
+
 import qualified FastString
 import qualified HsDecls
 import qualified OccName
@@ -25,26 +27,34 @@
 import           SrcLoc (unLoc)
 
 
-findTypeDecl :: [Char] -> ParsedSource -> [SearchResult]
-findTypeDecl name src =
+findTypeDecl :: Query -> ParsedSource -> [SearchResult]
+findTypeDecl q src =
   matchDecls src $ \decl ->
     fromMaybe False . match decl $
-         _TyClD . _DataDecl . _1 . _unloc . to (compareName name)
-      <> _TyClD . _SynDecl . _1 . _unloc . to (compareName name)
+         _TyClD . _DataDecl . _1 . _unloc . to (nameQuery q)
+      <> _TyClD . _SynDecl . _1 . _unloc . to (nameQuery q)
 
-findValueDecl :: [Char] -> ParsedSource -> [SearchResult]
-findValueDecl name src =
+findValueDecl :: Query -> ParsedSource -> [SearchResult]
+findValueDecl q src =
   matchDecls src $ \decl ->
     fromMaybe False . match decl $
-         _ValD . _FunBind . _1 . _unloc . to (compareName name)
-      <> _ValD . _VarBind . _1 . to (compareName name)
-      <> _SigD . _TypeSig . _1 . to (any (compareName name . unLoc))
+         _ValD . _FunBind . _1 . _unloc . to (nameQuery q)
+      <> _ValD . _VarBind . _1 . to (nameQuery q)
+      <> _SigD . _TypeSig . _1 . to (any (nameQuery q . unLoc))
 
 matchDecls :: ParsedSource -> (HsDecls.HsDecl RdrName.RdrName -> Bool) -> [SearchResult]
 matchDecls (ParsedSource (anns, locMod)) p =
   fmap (SearchResult anns) $
     L.filter (p . unLoc) (locMod ^. _unloc . _hsmodDecls)
 
+nameQuery :: Query -> RdrName.RdrName -> Bool
+nameQuery q n =
+  case q of
+    MatchSimple name ->
+      compareName name n
+    MatchRegex (Regex rex) ->
+      nameToString n =~ rex
+
 compareName :: [Char] -> RdrName.RdrName -> Bool
 compareName name n =
   case n of
@@ -54,6 +64,23 @@
       fastEq name (OccName.occNameFS ocn)
     _ ->
       False
+
+nameToFS :: RdrName.RdrName -> FastString.FastString
+nameToFS n =
+  OccName.occNameFS $
+    case n of
+      RdrName.Unqual ocn ->
+        ocn
+      RdrName.Qual _mod ocn ->
+        ocn
+      RdrName.Orig _mod ocn ->
+        ocn
+      RdrName.Exact name ->
+        name ^. _n_occ
+
+nameToString :: RdrName.RdrName -> [Char]
+nameToString =
+  FastString.unpackFS . nameToFS
 
 fastEq :: [Char] -> FastString.FastString -> Bool
 fastEq s fs =
