diff --git a/Control/Cond.hs b/Control/Cond.hs
--- a/Control/Cond.hs
+++ b/Control/Cond.hs
@@ -26,7 +26,8 @@
     , accept, ignore, norecurse, prune
 
     -- * Boolean logic
-    , matches, if_, when_, unless_, or_, and_, not_
+    , matches, ifM, whenM, unlessM
+    , if_, when_, unless_, or_, and_, not_
 
     -- * helper functions
     , recurse
@@ -179,7 +180,7 @@
         (Just r,  Continue)  -> getCondT (k r)
         (Just r,  Recurse n) -> getCondT (k r) >>= \case
             (v, Continue) -> return (v, Recurse (n >>= k))
-            x@_ -> return x
+            x             -> return x
     {-# INLINEABLE (>>=) #-}
 #if __GLASGOW_HASKELL__ >= 710
     {-# SPECIALIZE (>>=)
@@ -220,10 +221,7 @@
         case r of
             x@(Just _, _) -> return x
             _ -> g
-    {-# INLINEABLE (<|>) #-}
-#if __GLASGOW_HASKELL__ >= 710
-    {-# SPECIALIZE (<|>) :: CondT a IO a -> CondT a IO a -> CondT a IO a #-}
-#endif
+    {-# INLINE (<|>) #-}
 
 instance Monad m => MonadPlus (CondT a m) where
     mzero = CondT $ return recurse'
@@ -233,14 +231,13 @@
         case r of
             x@(Just _, _) -> return x
             _ -> g
-    {-# INLINEABLE mplus #-}
-#if __GLASGOW_HASKELL__ >= 710
-    {-# SPECIALIZE mplus :: CondT a IO a -> CondT a IO a -> CondT a IO a #-}
-#endif
+    {-# INLINE mplus #-}
 
 instance MonadError e m => MonadError e (CondT a m) where
     throwError = CondT . throwError
+    {-# INLINE throwError #-}
     catchError (CondT m) h = CondT $ m `catchError` \e -> getCondT (h e)
+    {-# INLINE catchError #-}
 
 instance MonadThrow m => MonadThrow (CondT a m) where
     throwM = CondT . throwM
@@ -310,6 +307,7 @@
 
 instance Monad m => MonadZip (CondT a m) where
     mzipWith = liftM2
+    {-# INLINE mzipWith #-}
 
 -- A deficiency of this instance is that recursion uses the same initial 'a'.
 instance MonadFix m => MonadFix (CondT a m) where
@@ -325,16 +323,14 @@
 runCondT :: Monad m => a -> CondT a m r -> m ((Maybe r, Maybe (CondT a m r)), a)
 runCondT a c@(CondT (StateT s)) = go `liftM` s a
   where
+    {-# INLINE go #-}
     go (p, a') = (second (recursorToMaybe c) p, a')
 
+    {-# INLINE recursorToMaybe #-}
     recursorToMaybe _ Stop        = Nothing
     recursorToMaybe p Continue    = Just p
     recursorToMaybe _ (Recurse n) = Just n
-{-# INLINEABLE runCondT #-}
-#if __GLASGOW_HASKELL__ >= 710
-{-# SPECIALIZE runCondT
-      :: a -> CondT a IO r -> IO ((Maybe r, Maybe (CondT a IO r)), a) #-}
-#endif
+{-# INLINE runCondT #-}
 
 runCond :: a -> Cond a r -> Maybe r
 runCond = ((fst . fst . runIdentity) .) . runCondT
@@ -393,85 +389,137 @@
 
 instance MonadQuery r m => MonadQuery r (ReaderT r m) where
     query = lift query
+    {-# INLINE query #-}
     queries = lift . queries
+    {-# INLINE queries #-}
     update = lift . update
+    {-# INLINE update #-}
     updates = lift . updates
+    {-# INLINE updates #-}
 
 instance (MonadQuery r m, Monoid w) => MonadQuery r (LazyRWS.RWST r w s m) where
     query = lift query
+    {-# INLINE query #-}
     queries = lift . queries
+    {-# INLINE queries #-}
     update = lift . update
+    {-# INLINE update #-}
     updates = lift . updates
+    {-# INLINE updates #-}
 
 instance (MonadQuery r m, Monoid w)
          => MonadQuery r (StrictRWS.RWST r w s m) where
     query = lift query
+    {-# INLINE query #-}
     queries = lift . queries
+    {-# INLINE queries #-}
     update = lift . update
+    {-# INLINE update #-}
     updates = lift . updates
+    {-# INLINE updates #-}
 
 -- All of these instances need UndecidableInstances, because they do not satisfy
 -- the coverage condition.
 
 instance MonadQuery r' m => MonadQuery r' (ContT r m) where
     query   = lift query
+    {-# INLINE query #-}
     queries = lift . queries
+    {-# INLINE queries #-}
     update = lift . update
+    {-# INLINE update #-}
     updates = lift . updates
+    {-# INLINE updates #-}
 
 instance (Error e, MonadQuery r m) => MonadQuery r (ErrorT e m) where
     query   = lift query
+    {-# INLINE query #-}
     queries = lift . queries
+    {-# INLINE queries #-}
     update = lift . update
+    {-# INLINE update #-}
     updates = lift . updates
+    {-# INLINE updates #-}
 
 instance MonadQuery r m => MonadQuery r (ExceptT e m) where
     query   = lift query
+    {-# INLINE query #-}
     queries = lift . queries
+    {-# INLINE queries #-}
     update = lift . update
+    {-# INLINE update #-}
     updates = lift . updates
+    {-# INLINE updates #-}
 
 instance MonadQuery r m => MonadQuery r (IdentityT m) where
     query   = lift query
+    {-# INLINE query #-}
     queries = lift . queries
+    {-# INLINE queries #-}
     update = lift . update
+    {-# INLINE update #-}
     updates = lift . updates
+    {-# INLINE updates #-}
 
 instance MonadQuery r m => MonadQuery r (ListT m) where
     query   = lift query
+    {-# INLINE query #-}
     queries = lift . queries
+    {-# INLINE queries #-}
     update = lift . update
+    {-# INLINE update #-}
     updates = lift . updates
+    {-# INLINE updates #-}
 
 instance MonadQuery r m => MonadQuery r (MaybeT m) where
     query   = lift query
+    {-# INLINE query #-}
     queries = lift . queries
+    {-# INLINE queries #-}
     update = lift . update
+    {-# INLINE update #-}
     updates = lift . updates
+    {-# INLINE updates #-}
 
 instance MonadQuery r m => MonadQuery r (Lazy.StateT s m) where
     query   = lift query
+    {-# INLINE query #-}
     queries = lift . queries
+    {-# INLINE queries #-}
     update = lift . update
+    {-# INLINE update #-}
     updates = lift . updates
+    {-# INLINE updates #-}
 
 instance MonadQuery r m => MonadQuery r (Strict.StateT s m) where
     query   = lift query
+    {-# INLINE query #-}
     queries = lift . queries
+    {-# INLINE queries #-}
     update = lift . update
+    {-# INLINE update #-}
     updates = lift . updates
+    {-# INLINE updates #-}
 
 instance (Monoid w, MonadQuery r m) => MonadQuery r (Lazy.WriterT w m) where
     query   = lift query
+    {-# INLINE query #-}
     queries = lift . queries
+    {-# INLINE queries #-}
     update = lift . update
+    {-# INLINE update #-}
     updates = lift . updates
+    {-# INLINE updates #-}
 
 instance (Monoid w, MonadQuery r m) => MonadQuery r (Strict.WriterT w m) where
     query   = lift query
+    {-# INLINE query #-}
     queries = lift . queries
+    {-# INLINE queries #-}
     update = lift . update
+    {-# INLINE update #-}
     updates = lift . updates
+    {-# INLINE updates #-}
 
 guardM :: MonadPlus m => m Bool -> m ()
 guardM = (>>= guard)
@@ -515,8 +563,7 @@
 norecurse = CondT $ return (Just (), Stop)
 {-# INLINE norecurse #-}
 
--- | 'prune' is a synonym for both ignoring an entry and its descendents. It
---   is the same as @ignore >> norecurse@.
+-- | 'prune' is a synonym for both ignoring an entry and its descendents.
 prune :: Monad m => CondT a m r
 prune = CondT $ return (Nothing, Stop)
 {-# INLINE prune #-}
@@ -533,6 +580,10 @@
 matches m = (const True `liftM` m) `mplus` return False
 {-# INLINE matches #-}
 
+ifM :: Monad m => m Bool -> m s -> m s -> m s
+ifM c x y = c >>= \b -> if b then x else y
+{-# INLINE ifM #-}
+
 -- | A variant of ifM which branches on whether the condition succeeds or not.
 --   Note that @if_ x@ is equivalent to @ifM (matches x)@, and is provided
 --   solely for convenience.
@@ -547,6 +598,10 @@
 if_ c x y = matches c >>= \b -> if b then x else y
 {-# INLINE if_ #-}
 
+whenM :: Monad m => m Bool -> m s -> m ()
+whenM c x = ifM c (x >> return ()) (return ())
+{-# INLINE whenM #-}
+
 -- | 'when_' is just like 'when', except that it executes the body if the
 --   condition passes, rather than based on a Bool value.
 --
@@ -559,6 +614,10 @@
 when_ :: MonadPlus m => m r -> m s -> m ()
 when_ c x = if_ c (x >> return ()) (return ())
 {-# INLINE when_ #-}
+
+unlessM :: Monad m => m Bool -> m s -> m ()
+unlessM c x = ifM c (return ()) (x >> return ())
+{-# INLINE unlessM #-}
 
 -- | 'when_' is just like 'when', except that it executes the body if the
 --   condition fails, rather than based on a Bool value.
diff --git a/hierarchy.cabal b/hierarchy.cabal
--- a/hierarchy.cabal
+++ b/hierarchy.cabal
@@ -1,5 +1,5 @@
 name:          hierarchy
-version:       0.3.1
+version:       0.3.1.1
 synopsis:      Pipes-based library for predicated traversal of generated trees
 description:   Pipes-based library for predicated traversal of generated trees
 homepage:      https://github.com/jwiegley/hierarchy
@@ -23,15 +23,15 @@
       Control.Cond
     , Pipes.Tree
   build-depends:       
-      base                >=4.7  && <4.9
-    , transformers        >=0.3  && <0.5
-    , transformers-base   >=0.3  && <0.5
-    , transformers-compat >=0.3  && <0.5
+      base                >=4.7  && <4.10
+    , transformers        >=0.3  && <0.6
+    , transformers-base   >=0.3  && <0.6
+    , transformers-compat >=0.3  && <0.6
     , exceptions          >=0.8  && <0.9
     , mmorph              >=1.0  && <1.1
     , mtl                 >=2.1  && <2.3
     , monad-control       >=1.0  && <1.1
-    , semigroups          >=0.16 && <0.17
+    , semigroups          >=0.16 && <0.19
     , free                >=4.12 && <4.13
     , pipes               >=4.1  && <4.2
   default-language:    Haskell2010
@@ -58,7 +58,7 @@
       base >=3
     , hierarchy
     , pipes              >=4.1  && <4.2
-    , transformers       >=0.3  && <0.5
+    , transformers       >=0.3  && <0.6
     , mtl                >=2.1  && <2.3
     , hspec              >=1.4.4
     , hspec-expectations >=0.3
