diff --git a/Control/Cond.hs b/Control/Cond.hs
deleted file mode 100644
--- a/Control/Cond.hs
+++ /dev/null
@@ -1,688 +0,0 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE DeriveFunctor #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE FunctionalDependencies #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE LambdaCase #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE RankNTypes #-}
-{-# LANGUAGE RecursiveDo #-}
-{-# LANGUAGE TupleSections #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE UndecidableInstances #-}
-
-{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}
-
-module Control.Cond
-    ( CondT, Cond
-
-    -- * Executing CondT
-    , runCondT, runCond, execCondT, evalCondT, test
-
-    -- * Promotions
-    , MonadQuery(..), guardM, guard_, guardM_, apply, consider
-
-    -- * Basic conditionals
-    , accept, ignore, norecurse, prune
-
-    -- * Boolean logic
-    , matches, ifM, whenM, unlessM
-    , if_, when_, unless_, or_, and_, not_
-
-    -- * helper functions
-    , recurse
-    )
-    where
-
-import           Control.Applicative
-import           Control.Arrow (second)
-import           Control.Monad hiding (mapM_, sequence_)
-import           Control.Monad.Base
-import           Control.Monad.Catch
-import           Control.Monad.Cont.Class as C
-import           Control.Monad.Error.Class as E
-import           Control.Monad.Fix
-import           Control.Monad.Morph as M
-import           Control.Monad.Reader.Class as R
-import           Control.Monad.State.Class as S
-import           Control.Monad.Trans
-import           Control.Monad.Trans.Cont (ContT(..))
-import           Control.Monad.Trans.Control
-import           Control.Monad.Trans.Error (ErrorT(..))
-import           Control.Monad.Trans.Except (ExceptT(..))
-import           Control.Monad.Trans.Identity (IdentityT(..))
-import           Control.Monad.Trans.List (ListT(..))
-import           Control.Monad.Trans.Maybe (MaybeT(..))
-import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS
-import qualified Control.Monad.Trans.RWS.Strict as StrictRWS
-import           Control.Monad.Trans.Reader (ReaderT(..))
-import           Control.Monad.Trans.State (StateT(..))
-import qualified Control.Monad.Trans.State.Lazy as Lazy
-import qualified Control.Monad.Trans.State.Strict as Strict
-import qualified Control.Monad.Trans.Writer.Lazy as Lazy
-import qualified Control.Monad.Trans.Writer.Strict as Strict
-import           Control.Monad.Writer.Class
-import           Control.Monad.Zip
-import           Data.Foldable
-import           Data.Functor.Identity
-import           Data.Monoid hiding ((<>))
-import           Data.Semigroup
-import           Prelude hiding (mapM_, foldr1, sequence_)
-
-data Recursor a m r = Stop | Recurse (CondT a m r) | Continue
-    deriving Functor
-
-instance Semigroup (Recursor a m r) where
-    Stop      <> _         = Stop
-    _         <> Stop      = Stop
-    Recurse n <> _         = Recurse n
-    _         <> Recurse n = Recurse n
-    _         <> _         = Continue
-    {-# INLINE (<>) #-}
-
-instance Monoid (Recursor a m r) where
-    mempty  = Continue
-    {-# INLINE mempty #-}
-    mappend = (<>)
-    {-# INLINE mappend #-}
-
-instance MFunctor (Recursor a) where
-    hoist _   Stop        = Stop
-    hoist nat (Recurse n) = Recurse (hoist nat n)
-    hoist _   Continue    = Continue
-    {-# INLINE hoist #-}
-
-type CondR a m r = (Maybe r, Recursor a m r)
-
-accept' :: r -> CondR a m r
-accept' x = (Just x, Continue)
-{-# INLINE accept' #-}
-
-recurse' :: CondR a m r
-recurse' = (Nothing, Continue)
-{-# INLINE recurse' #-}
-
--- | 'CondT' and its related combinators form a DSL to express whether, given
--- an item of type 'a': that item passes the predicate, and/or if recursion
--- should be performed from that item, should it relate to the branch of a
--- tree. This is used to build predicates that can guide recursive traversals.
---
--- For example, when recursing files in a directory tree, there are several
--- scenarios that 'CondT' maybe consider:
---
---   - Whether the entry at a given path is of interest, independent from its
---     type (files or directories)
---   - If the path is a directory, if the directory should be recursed into.
---
--- Yes or no answers are accepted for either criterion. This means that the
--- answer is "no" to both questions for a given directory, the combinator
--- 'prune' should be used both to ignore the entry itself, and to prevent
--- recursion into its contents.
---
--- Several different predicate types may be promoted to 'CondT':
---
---   [@Bool@]                  Using 'guard'
---
---   [@m Bool@]                Using 'guardM'
---
---   [@a -> Bool@]              Using 'guard_'
---
---   [@a -> m Bool@]            Using 'guardM_'
---
---   [@a -> m (Maybe r)@]       Using 'apply'
---
---   [@a -> m (Maybe (r, a))@]  Using 'consider'
---
--- Here is a trivial example:
---
--- @
--- flip runCondT 42 $ do
---   guard_ even
---   liftIO $ putStrLn "42 must be even to reach here"
---   guard_ odd \<|\> guard_ even
---   guard_ (== 42)
--- @
---
--- If 'CondT' is executed using 'runCondT', it returns a @Maybe r@ if the
--- predicate matched. It should usually be run with 'applyCondT', which calls
--- a continuation indicating wether recursion should be performed.
-newtype CondT a m r = CondT { getCondT :: StateT a m (CondR a m r) }
-    deriving Functor
-
-type Cond a = CondT a Identity
-
-instance (Monad m, Semigroup r) => Semigroup (CondT a m r) where
-    (<>) = liftM2 (<>)
-    {-# INLINE (<>) #-}
-
-instance (Monad m, Monoid r) => Monoid (CondT a m r) where
-    mempty  = CondT $ return mempty
-    {-# INLINE mempty #-}
-    mappend = liftM2 mappend
-    {-# INLINE mappend #-}
-
-instance Monad m => Applicative (CondT a m) where
-    pure  = return
-    {-# INLINE pure #-}
-    (<*>) = ap
-    {-# INLINE (<*>) #-}
-
-instance Monad m => Monad (CondT a m) where
-    return = CondT . return . accept'
-    {-# INLINE return #-}
-    fail _ = mzero
-    {-# INLINE fail #-}
-    CondT m >>= k = CondT $ m >>= \case
-        (Nothing, Stop)      -> return (Nothing, Stop)
-        (Nothing, Continue)  -> return (Nothing, Continue)
-        (Nothing, Recurse n) -> return (Nothing, Recurse (n >>= k))
-        (Just r,  Stop)      -> fmap (const Stop) `liftM` getCondT (k r)
-        (Just r,  Continue)  -> getCondT (k r)
-        (Just r,  Recurse n) -> getCondT (k r) >>= \case
-            (v, Continue) -> return (v, Recurse (n >>= k))
-            x             -> return x
-    {-# INLINEABLE (>>=) #-}
--- #if __GLASGOW_HASKELL__ >= 710
---     {-# SPECIALIZE (>>=)
---           :: CondT e IO a -> (a -> CondT e IO b) -> CondT e IO b #-}
--- #endif
-
-instance MonadReader r m => MonadReader r (CondT a m) where
-    ask = lift R.ask
-    {-# INLINE ask #-}
-    local f (CondT m) = CondT $ R.local f m
-    {-# INLINE local #-}
-    reader = lift . R.reader
-    {-# INLINE reader #-}
-
-instance MonadWriter w m => MonadWriter w (CondT a m) where
-    writer   = lift . writer
-    {-# INLINE writer #-}
-    tell     = lift . tell
-    {-# INLINE tell #-}
-    listen m = m >>= lift . listen . return
-    {-# INLINE listen #-}
-    pass m   = m >>= lift . pass . return
-    {-# INLINE pass #-}
-
-instance MonadState s m => MonadState s (CondT a m) where
-    get = lift S.get
-    {-# INLINE get #-}
-    put = lift . S.put
-    {-# INLINE put #-}
-    state = lift . S.state
-    {-# INLINE state #-}
-
-instance Monad m => Alternative (CondT a m) where
-    empty = CondT $ return recurse'
-    {-# INLINE empty #-}
-    CondT f <|> CondT g = CondT $ do
-        r <- f
-        case r of
-            x@(Just _, _) -> return x
-            _ -> g
-    {-# INLINE (<|>) #-}
-
-instance Monad m => MonadPlus (CondT a m) where
-    mzero = CondT $ return recurse'
-    {-# INLINE mzero #-}
-    mplus (CondT f) (CondT g) = CondT $ do
-        r <- f
-        case r of
-            x@(Just _, _) -> return x
-            _ -> g
-    {-# 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
-    {-# INLINE throwM #-}
-
-instance MonadCatch m => MonadCatch (CondT a m) where
-    catch (CondT m) c = CondT $ m `catch` \e -> getCondT (c e)
-    {-# INLINE catch #-}
-#if MIN_VERSION_exceptions(0,6,0)
-
-instance MonadMask m => MonadMask (CondT a m) where
-#endif
-    mask a = CondT $ mask $ \u -> getCondT (a $ q u)
-      where q u = CondT . u . getCondT
-    {-# INLINE mask #-}
-    uninterruptibleMask a =
-        CondT $ uninterruptibleMask $ \u -> getCondT (a $ q u)
-      where q u = CondT . u . getCondT
-    {-# INLINEABLE uninterruptibleMask #-}
-
-instance MonadBase b m => MonadBase b (CondT a m) where
-    liftBase m = CondT $ liftM accept' $ liftBase m
-    {-# INLINE liftBase #-}
-
-instance MonadIO m => MonadIO (CondT a m) where
-    liftIO m = CondT $ liftM accept' $ liftIO m
-    {-# INLINE liftIO #-}
-
-instance MonadTrans (CondT a) where
-    lift m = CondT $ liftM accept' $ lift m
-    {-# INLINE lift #-}
-
-#if MIN_VERSION_monad_control(1,0,0)
-instance MonadBaseControl b m => MonadBaseControl b (CondT r m) where
-    type StM (CondT r m) a = StM m (CondR r m a, r)
-    liftBaseWith f = CondT $ StateT $ \s ->
-        liftM (\x -> (accept' x, s)) $ liftBaseWith $ \runInBase ->
-            f $ \k -> runInBase $ runStateT (getCondT k) s
-    {-# INLINABLE liftBaseWith #-}
-    restoreM = CondT . StateT . const . restoreM
-    {-# INLINE restoreM #-}
-#else
-instance MonadBaseControl b m => MonadBaseControl b (CondT r m) where
-    newtype StM (CondT r m) a =
-        CondTStM { unCondTStM :: StM m (Result r m a, r) }
-    liftBaseWith f = CondT $ StateT $ \s ->
-        liftM (\x -> (accept' x, s)) $ liftBaseWith $ \runInBase -> f $ \k ->
-            liftM CondTStM $ runInBase $ runStateT (getCondT k) s
-    {-# INLINEABLE liftBaseWith #-}
-    restoreM = CondT . StateT . const . restoreM . unCondTStM
-    {-# INLINE restoreM #-}
-#endif
-
-instance MFunctor (CondT a) where
-    hoist nat (CondT m) = CondT $ hoist nat (fmap (hoist nat) `liftM` m)
-    {-# INLINE hoist #-}
-
--- This won't work for StateT-like types
--- instance MMonad (CondT a) where
---     embed f m = undefined
---     {-# INLINE embed #-}
-
-instance MonadCont m => MonadCont (CondT a m) where
-    callCC f = CondT $ StateT $ \a ->
-        callCC $ \k -> flip runStateT a $ getCondT $ f $ \r ->
-            CondT $ StateT $ \a' -> k ((Just r, Continue), a')
-
-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
-    mfix f = CondT $ StateT $ \a -> mdo
-        ((mb, n), a') <- case mb of
-            Nothing -> return ((mb, n), a')
-            Just b  -> runStateT (getCondT (f b)) a
-        return ((mb, n), a')
-
--- | Apply a condition to an input value, returning a (possibly) updated copy
--- of that value if it matches, and the next 'CondT' to use if recursion into
--- that value was indicated.
-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
-{-# INLINE runCondT #-}
-
-runCond :: a -> Cond a r -> Maybe r
-runCond = ((fst . fst . runIdentity) .) . runCondT
-{-# INLINE runCond #-}
-
-execCondT :: Monad m => a -> CondT a m r -> m (Maybe a, Maybe (CondT a m r))
-execCondT a c = go `liftM` runCondT a c
-  where
-    go ((mr, mnext), a') = (const a' <$> mr, mnext)
-{-# INLINE execCondT #-}
-
-evalCondT :: Monad m => a -> CondT a m r -> m (Maybe r)
-evalCondT a c = go `liftM` runCondT a c
-  where
-    go ((mr, _), _) = mr
-{-# INLINE evalCondT #-}
-
--- | A specialized variant of 'runCondT' that simply returns True or False.
---
--- >>> let good = guard_ (== "foo.hs") :: Cond String ()
--- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()
--- >>> runIdentity $ test "foo.hs" $ not_ bad >> return "Success"
--- True
--- >>> runIdentity $ test "foo.hs" $ not_ good >> return "Shouldn't reach here"
--- False
-test :: Monad m => a -> CondT a m r -> m Bool
-test a c = go `liftM` runCondT a c
-  where
-    go ((Nothing, _), _) = False
-    go ((Just _, _), _)  = True
-{-# INLINE test #-}
-
--- | 'MonadQuery' is a custom version of 'MonadReader', created so that users
--- could still have their own 'MonadReader' accessible within conditionals.
-class Monad m => MonadQuery a m | m -> a where
-    query :: m a
-    queries :: (a -> b) -> m b
-    update :: a -> m ()
-    updates :: (a -> a) -> m ()
-
-instance Monad m => MonadQuery a (CondT a m) where
-    -- | Returns the item currently under consideration.
-    query = CondT $ gets accept'
-    {-# INLINE query #-}
-
-    -- | Returns the item currently under consideration while applying a
-    -- function, in the spirit of 'asks'.
-    queries f = CondT $ state (\a -> (accept' (f a), a))
-    {-# INLINE queries #-}
-
-    update a = CondT $ liftM accept' $ put a
-    {-# INLINE update #-}
-
-    updates f = CondT $ liftM accept' $ modify f
-    {-# INLINE updates #-}
-
-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)
-{-# INLINE guardM #-}
-
-guard_ :: (MonadPlus m, MonadQuery a m) => (a -> Bool) -> m ()
-guard_ f = query >>= guard . f
-{-# INLINE guard_ #-}
-
-guardM_ :: (MonadPlus m, MonadQuery a m) => (a -> m Bool) -> m ()
-guardM_ f = query >>= guardM . f
-{-# INLINE guardM_ #-}
-
--- | Apply a value-returning predicate. Note that whether or not this return a
--- 'Just' value, recursion will be performed in the entry itself, if
--- applicable.
-apply :: (MonadPlus m, MonadQuery a m) => (a -> m (Maybe r)) -> m r
-apply = queries >=> (>>= maybe mzero return)
-{-# INLINE apply #-}
-
--- | Consider an element, as 'apply', but returning a mutated form of the
--- element. This can be used to apply optimizations to speed future
--- conditions.
-consider :: (MonadPlus m, MonadQuery a m) => (a -> m (Maybe (r, a))) -> m r
-consider = queries >=> (>>= maybe mzero (\(r, a') -> const r `liftM` update a'))
-{-# INLINE consider #-}
-
-accept :: MonadPlus m => m ()
-accept = return ()
-{-# INLINE accept #-}
-
--- | 'ignore' ignores the current entry, but allows recursion into its
---   descendents.  This is the same as 'empty'.
-ignore :: MonadPlus m => m r
-ignore = mzero
-{-# INLINE ignore #-}
-
--- | 'norecurse' prevents recursion into the current entry's descendents, but
---   does not ignore the entry itself.
-norecurse :: Monad m => CondT a m ()
-norecurse = CondT $ return (Just (), Stop)
-{-# INLINE 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 #-}
-
--- | Return True or False depending on whether the given condition matches or
---   not.  This differs from simply stating the condition in that it itself
---   always succeeds.
---
--- >>> runCond "foo.hs" $ matches (guard =<< queries (== "foo.hs"))
--- Just True
--- >>> runCond "foo.hs" $ matches (guard =<< queries (== "foo.hi"))
--- Just False
-matches :: MonadPlus m => m r -> m Bool
-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.
---
--- >>> let good = guard_ (== "foo.hs") :: Cond String ()
--- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()
--- >>> runCond "foo.hs" $ if_ good (return "Success") (return "Failure")
--- Just "Success"
--- >>> runCond "foo.hs" $ if_ bad (return "Success") (return "Failure")
--- Just "Failure"
-if_ :: MonadPlus m => m r -> m s -> m s -> m s
-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.
---
--- >>> let good = guard_ (== "foo.hs") :: Cond String ()
--- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()
--- >>> runCond "foo.hs" $ when_ good ignore
--- Nothing
--- >>> runCond "foo.hs" $ when_ bad ignore
--- Just ()
-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.
---
--- >>> let good = guard_ (== "foo.hs") :: Cond String ()
--- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()
--- >>> runCond "foo.hs" $ unless_ bad ignore
--- Nothing
--- >>> runCond "foo.hs" $ unless_ good ignore
--- Just ()
-unless_ :: MonadPlus m => m r -> m s -> m ()
-unless_ c x = if_ c (return ()) (x >> return ())
-{-# INLINE unless_ #-}
-
--- | Check whether at least one of the given conditions is true.  This is a
---   synonym for 'Data.Foldable.asum'.
---
--- >>> let good = guard_ (== "foo.hs") :: Cond String ()
--- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()
--- >>> runCond "foo.hs" $ or_ [bad, good]
--- Just ()
--- >>> runCond "foo.hs" $ or_ [bad]
--- Nothing
-or_ :: MonadPlus m => [m r] -> m r
-or_ = Data.Foldable.msum
-{-# INLINE or_ #-}
-
--- | Check that all of the given conditions are true.  This is a synonym for
---   'Data.Foldable.sequence_'.
---
--- >>> let good = guard_ (== "foo.hs") :: Cond String ()
--- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()
--- >>> runCond "foo.hs" $ and_ [bad, good]
--- Nothing
--- >>> runCond "foo.hs" $ and_ [good]
--- Just ()
-and_ :: MonadPlus m => [m r] -> m ()
-and_ = sequence_
-{-# INLINE and_ #-}
-
--- | 'not_' inverts the meaning of the given predicate.
---
--- >>> let good = guard_ (== "foo.hs") :: Cond String ()
--- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()
--- >>> runCond "foo.hs" $ not_ bad >> return "Success"
--- Just "Success"
--- >>> runCond "foo.hs" $ not_ good >> return "Shouldn't reach here"
--- Nothing
-not_ :: MonadPlus m => m r -> m ()
-not_ c = if_ c ignore accept
-{-# INLINE not_ #-}
-
--- | 'recurse' changes the recursion predicate for any child elements.  For
---   example, the following file-finding predicate looks for all @*.hs@ files,
---   but under any @.git@ directory looks only for a file named @config@:
---
--- @
--- if_ (name_ \".git\" \>\> directory)
---     (ignore \>\> recurse (name_ \"config\"))
---     (glob \"*.hs\")
--- @
---
--- NOTE: If this code had used @recurse (glob \"*.hs\"))@ instead in the else
--- case, it would have meant that @.git@ is only looked for at the top-level
--- of the search (i.e., the top-most element).
-recurse :: Monad m => CondT a m r -> CondT a m r
-recurse c = CondT $ fmap (const (Recurse c)) `liftM` getCondT c
-{-# INLINE recurse #-}
diff --git a/Pipes/Tree.hs b/Pipes/Tree.hs
deleted file mode 100644
--- a/Pipes/Tree.hs
+++ /dev/null
@@ -1,56 +0,0 @@
-{-# LANGUAGE RankNTypes #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-
-module Pipes.Tree where
-
-import Control.Comonad.Trans.Cofree
-import Control.Cond
-import Pipes
-
--- | A 'TreeT' is a tree of values, where the (possible) branches are
--- 'ListT's.
-type TreeT m = CofreeT Maybe (ListT m)
-
--- | Turn a generated list into a 'ListT'.
-selectEach :: Monad m => m [a] -> ListT m a
-selectEach m = Select $ each =<< lift m
-
--- | Descend one level into a 'TreeT', yielding a list of values and their
--- possible associated trees.
-descend :: Monad m => TreeT m a -> ListT m (a, Maybe (TreeT m a))
-descend (CofreeT (Select t)) = Select $ for t $ \(a :< mp) -> yield (a, mp)
-{-# INLINE descend #-}
-
--- | Perform a depth-first traversal of a 'TreeT', yielding a 'ListT' of its
--- contents. Note that breadth-first traversals cannot offer static memory
--- guarantees, so they are not provided by this module.
-walk :: Monad m => TreeT m a -> ListT m a
-walk (CofreeT (Select t)) = Select $ for t $ \(a :< mp) ->
-    yield a >> maybe (return ()) (enumerate . walk) mp
-{-# INLINEABLE walk #-}
-
--- | Given a 'TreeT', produce another 'TreeT' which yields only those elements
--- (and sub-trees) matching the given monadic conditional. This conditional
--- (see 'Control.Cond.CondT') can choose both elements and points of
--- recursion, making it capable of expressing any tree traversal in the form
--- of a predicate DSL. This differs from an expression-based traversal, like
--- XPath or Lens, in that effects in 'm' may be used to guide selection.
---
--- For example, to print all Haskell files under the current directory:
---
--- @
---     let files = winnow (directoryFiles ".") $ do
---             path <- query
---             liftIO $ putStrLn $ "Considering " ++ path
---             when (path @`elem@` [".@/@.git", ".@/@dist", ".@/@result"])
---                 prune  -- ignore these, and don't recurse into them
---             guard_ (".hs" @`isInfixOf@`)  -- implicitly references 'path'
---     runEffect $ for (enumerate (walk files)) $ liftIO . print
--- @
-winnow :: Monad m => TreeT m a -> CondT a m () -> TreeT m a
-winnow (CofreeT (Select t)) p = CofreeT $ Select $ for t $ \(a :< mst) -> do
-    (mval, mnext) <- lift $ execCondT a p
-    let mnext' = winnow <$> mst <*> mnext
-    case mval of
-        Nothing -> maybe (return ()) (enumerate . runCofreeT) mnext'
-        Just a' -> yield (a' :< mnext')
diff --git a/hierarchy.cabal b/hierarchy.cabal
--- a/hierarchy.cabal
+++ b/hierarchy.cabal
@@ -1,64 +1,71 @@
-name:          hierarchy
-version:       0.3.1.4
-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
-license:       BSD3
-license-file:  LICENSE
-author:        John Wiegley
-maintainer:    damian.nadales@gmail.com
-copyright:     Copyright 2015 (c) John Wiegley. All Rights Reserved.
-category:      Data
-build-type:    Simple
-cabal-version: >=1.10
+-- This file has been generated from package.yaml by hpack version 0.27.0.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 2596f3b56ac8cc1f0530263376774a0928ed672af04accda1fdf311d298fb764
 
-Source-repository head
+name:           hierarchy
+version:        1.0.0
+synopsis:       Predicated traversal of generated trees
+description:    Predicated traversal of generated trees.
+category:       Data
+homepage:       https://github.com/jwiegley/hierarchy#readme
+bug-reports:    https://github.com/jwiegley/hierarchy/issues
+author:         John Wiegley
+maintainer:     johnw@newartisans.com
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+
+source-repository head
   type: git
-  location: git://github.com/jwiegley/hierarchy.git
+  location: https://github.com/jwiegley/hierarchy
 
 library
-  ghc-options:      -Wall -funbox-strict-fields
-  include-dirs:     .
-  exposed-modules:     
+  exposed-modules:
       Control.Cond
-    , Pipes.Tree
-  build-depends:       
-      base                >=4.7  && <4.12
-    , transformers        >=0.3  && <0.7
-    , transformers-base   >=0.3  && <0.7
-    , transformers-compat >=0.3  && <0.7
-    , exceptions          >=0.8  && <0.9
-    , mmorph              >=1.0  && <1.3
-    , mtl                 >=2.1  && <2.4
-    , monad-control       >=1.0  && <1.1
-    , semigroups          >=0.16 && <0.19
-    , free                >=4.10 && < 6
-    , pipes               >=4.1  && < 4.5
-  default-language:    Haskell2010
+      Hierarchy
+  other-modules:
+      Paths_hierarchy
+  hs-source-dirs:
+      src
+  build-depends:
+      base >=4.7 && <4.12
+    , exceptions >=0.8 && <0.9
+    , free >=4.12 && <6
+    , mmorph >=1.0 && <1.2
+    , monad-control >=1.0 && <1.1
+    , mtl >=2.1 && <2.4
+    , transformers >=0.3 && <0.7
+    , transformers-base >=0.3 && <0.7
+    , transformers-compat >=0.3 && <0.7
+  if impl(ghc < 8.2.0)
+    build-depends:
+        semigroups >=0.16 && <0.19
+  default-language: Haskell2010
 
-Test-suite doctests
-  default-language: Haskell98
-  type:    exitcode-stdio-1.0
+test-suite doctests
+  type: exitcode-stdio-1.0
   main-is: doctest.hs
-  hs-source-dirs: test
-  build-depends:      
-      base
-    , directory    >=1.0
-    , doctest      >=0.8
-    , filepath     >=1.3
-    , semigroups   >=0.4
-
-test-suite test
+  other-modules:
+      Paths_hierarchy
+  hs-source-dirs:
+      test
+  build-depends:
+      base >=4.7 && <4.12
+    , directory >=1.0
+    , doctest >=0.8
+    , exceptions >=0.8 && <0.9
+    , filepath >=1.3
+    , free >=4.12 && <6
+    , mmorph >=1.0 && <1.2
+    , monad-control >=1.0 && <1.1
+    , mtl >=2.1 && <2.4
+    , transformers >=0.3 && <0.7
+    , transformers-base >=0.3 && <0.7
+    , transformers-compat >=0.3 && <0.7
+  if impl(ghc < 8.2.0)
+    build-depends:
+        semigroups >=0.16 && <0.19
   default-language: Haskell2010
-  type:             exitcode-stdio-1.0
-  ghc-options:      -Wall -fno-warn-deprecated-flags -threaded
-  hs-source-dirs:   test
-  main-is:          Main.hs
-  build-depends: 
-      base >=3
-    , hierarchy
-    , pipes              >=4.1  && <4.5
-    , transformers       >=0.3  && <0.7
-    , mtl                >=2.1  && <2.4
-    , hspec              >=1.4.4
-    , hspec-expectations >=0.3
diff --git a/src/Control/Cond.hs b/src/Control/Cond.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Cond.hs
@@ -0,0 +1,688 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE RecursiveDo #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE UndecidableInstances #-}
+
+{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}
+
+module Control.Cond
+    ( CondT, Cond
+
+    -- * Executing CondT
+    , runCondT, runCond, execCondT, evalCondT, test
+
+    -- * Promotions
+    , MonadQuery(..), guardM, guard_, guardM_, apply, consider
+
+    -- * Basic conditionals
+    , accept, ignore, norecurse, prune
+
+    -- * Boolean logic
+    , matches, ifM, whenM, unlessM
+    , if_, when_, unless_, or_, and_, not_
+
+    -- * helper functions
+    , recurse
+    )
+    where
+
+import           Control.Applicative
+import           Control.Arrow (second)
+import           Control.Monad hiding (mapM_, sequence_)
+import           Control.Monad.Base
+import           Control.Monad.Catch
+import           Control.Monad.Cont.Class as C
+import           Control.Monad.Error.Class as E
+import           Control.Monad.Fix
+import           Control.Monad.Morph as M
+import           Control.Monad.Reader.Class as R
+import           Control.Monad.State.Class as S
+import           Control.Monad.Trans
+import           Control.Monad.Trans.Cont (ContT(..))
+import           Control.Monad.Trans.Control
+import           Control.Monad.Trans.Error (ErrorT(..))
+import           Control.Monad.Trans.Except (ExceptT(..))
+import           Control.Monad.Trans.Identity (IdentityT(..))
+import           Control.Monad.Trans.List (ListT(..))
+import           Control.Monad.Trans.Maybe (MaybeT(..))
+import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS
+import qualified Control.Monad.Trans.RWS.Strict as StrictRWS
+import           Control.Monad.Trans.Reader (ReaderT(..))
+import           Control.Monad.Trans.State (StateT(..))
+import qualified Control.Monad.Trans.State.Lazy as Lazy
+import qualified Control.Monad.Trans.State.Strict as Strict
+import qualified Control.Monad.Trans.Writer.Lazy as Lazy
+import qualified Control.Monad.Trans.Writer.Strict as Strict
+import           Control.Monad.Writer.Class
+import           Control.Monad.Zip
+import           Data.Foldable
+import           Data.Functor.Identity
+import           Data.Monoid hiding ((<>))
+import           Data.Semigroup
+import           Prelude hiding (mapM_, foldr1, sequence_)
+
+data Recursor a m r = Stop | Recurse (CondT a m r) | Continue
+    deriving Functor
+
+instance Semigroup (Recursor a m r) where
+    Stop      <> _         = Stop
+    _         <> Stop      = Stop
+    Recurse n <> _         = Recurse n
+    _         <> Recurse n = Recurse n
+    _         <> _         = Continue
+    {-# INLINE (<>) #-}
+
+instance Monoid (Recursor a m r) where
+    mempty  = Continue
+    {-# INLINE mempty #-}
+    mappend = (<>)
+    {-# INLINE mappend #-}
+
+instance MFunctor (Recursor a) where
+    hoist _   Stop        = Stop
+    hoist nat (Recurse n) = Recurse (hoist nat n)
+    hoist _   Continue    = Continue
+    {-# INLINE hoist #-}
+
+type CondR a m r = (Maybe r, Recursor a m r)
+
+accept' :: r -> CondR a m r
+accept' x = (Just x, Continue)
+{-# INLINE accept' #-}
+
+recurse' :: CondR a m r
+recurse' = (Nothing, Continue)
+{-# INLINE recurse' #-}
+
+-- | 'CondT' and its related combinators form a DSL to express whether, given
+-- an item of type 'a': that item passes the predicate, and/or if recursion
+-- should be performed from that item, should it relate to the branch of a
+-- tree. This is used to build predicates that can guide recursive traversals.
+--
+-- For example, when recursing files in a directory tree, there are several
+-- scenarios that 'CondT' maybe consider:
+--
+--   - Whether the entry at a given path is of interest, independent from its
+--     type (files or directories)
+--   - If the path is a directory, if the directory should be recursed into.
+--
+-- Yes or no answers are accepted for either criterion. This means that the
+-- answer is "no" to both questions for a given directory, the combinator
+-- 'prune' should be used both to ignore the entry itself, and to prevent
+-- recursion into its contents.
+--
+-- Several different predicate types may be promoted to 'CondT':
+--
+--   [@Bool@]                  Using 'guard'
+--
+--   [@m Bool@]                Using 'guardM'
+--
+--   [@a -> Bool@]              Using 'guard_'
+--
+--   [@a -> m Bool@]            Using 'guardM_'
+--
+--   [@a -> m (Maybe r)@]       Using 'apply'
+--
+--   [@a -> m (Maybe (r, a))@]  Using 'consider'
+--
+-- Here is a trivial example:
+--
+-- @
+-- flip runCondT 42 $ do
+--   guard_ even
+--   liftIO $ putStrLn "42 must be even to reach here"
+--   guard_ odd \<|\> guard_ even
+--   guard_ (== 42)
+-- @
+--
+-- If 'CondT' is executed using 'runCondT', it returns a @Maybe r@ if the
+-- predicate matched. It should usually be run with 'applyCondT', which calls
+-- a continuation indicating wether recursion should be performed.
+newtype CondT a m r = CondT { getCondT :: StateT a m (CondR a m r) }
+    deriving Functor
+
+type Cond a = CondT a Identity
+
+instance (Monad m, Semigroup r) => Semigroup (CondT a m r) where
+    (<>) = liftM2 (<>)
+    {-# INLINE (<>) #-}
+
+instance (Monad m, Monoid r) => Monoid (CondT a m r) where
+    mempty  = CondT $ return mempty
+    {-# INLINE mempty #-}
+    mappend = liftM2 mappend
+    {-# INLINE mappend #-}
+
+instance Monad m => Applicative (CondT a m) where
+    pure  = return
+    {-# INLINE pure #-}
+    (<*>) = ap
+    {-# INLINE (<*>) #-}
+
+instance Monad m => Monad (CondT a m) where
+    return = CondT . return . accept'
+    {-# INLINE return #-}
+    fail _ = mzero
+    {-# INLINE fail #-}
+    CondT m >>= k = CondT $ m >>= \case
+        (Nothing, Stop)      -> return (Nothing, Stop)
+        (Nothing, Continue)  -> return (Nothing, Continue)
+        (Nothing, Recurse n) -> return (Nothing, Recurse (n >>= k))
+        (Just r,  Stop)      -> fmap (const Stop) `liftM` getCondT (k r)
+        (Just r,  Continue)  -> getCondT (k r)
+        (Just r,  Recurse n) -> getCondT (k r) >>= \case
+            (v, Continue) -> return (v, Recurse (n >>= k))
+            x             -> return x
+    {-# INLINEABLE (>>=) #-}
+-- #if __GLASGOW_HASKELL__ >= 710
+--     {-# SPECIALIZE (>>=)
+--           :: CondT e IO a -> (a -> CondT e IO b) -> CondT e IO b #-}
+-- #endif
+
+instance MonadReader r m => MonadReader r (CondT a m) where
+    ask = lift R.ask
+    {-# INLINE ask #-}
+    local f (CondT m) = CondT $ R.local f m
+    {-# INLINE local #-}
+    reader = lift . R.reader
+    {-# INLINE reader #-}
+
+instance MonadWriter w m => MonadWriter w (CondT a m) where
+    writer   = lift . writer
+    {-# INLINE writer #-}
+    tell     = lift . tell
+    {-# INLINE tell #-}
+    listen m = m >>= lift . listen . return
+    {-# INLINE listen #-}
+    pass m   = m >>= lift . pass . return
+    {-# INLINE pass #-}
+
+instance MonadState s m => MonadState s (CondT a m) where
+    get = lift S.get
+    {-# INLINE get #-}
+    put = lift . S.put
+    {-# INLINE put #-}
+    state = lift . S.state
+    {-# INLINE state #-}
+
+instance Monad m => Alternative (CondT a m) where
+    empty = CondT $ return recurse'
+    {-# INLINE empty #-}
+    CondT f <|> CondT g = CondT $ do
+        r <- f
+        case r of
+            x@(Just _, _) -> return x
+            _ -> g
+    {-# INLINE (<|>) #-}
+
+instance Monad m => MonadPlus (CondT a m) where
+    mzero = CondT $ return recurse'
+    {-# INLINE mzero #-}
+    mplus (CondT f) (CondT g) = CondT $ do
+        r <- f
+        case r of
+            x@(Just _, _) -> return x
+            _ -> g
+    {-# 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
+    {-# INLINE throwM #-}
+
+instance MonadCatch m => MonadCatch (CondT a m) where
+    catch (CondT m) c = CondT $ m `catch` \e -> getCondT (c e)
+    {-# INLINE catch #-}
+#if MIN_VERSION_exceptions(0,6,0)
+
+instance MonadMask m => MonadMask (CondT a m) where
+#endif
+    mask a = CondT $ mask $ \u -> getCondT (a $ q u)
+      where q u = CondT . u . getCondT
+    {-# INLINE mask #-}
+    uninterruptibleMask a =
+        CondT $ uninterruptibleMask $ \u -> getCondT (a $ q u)
+      where q u = CondT . u . getCondT
+    {-# INLINEABLE uninterruptibleMask #-}
+
+instance MonadBase b m => MonadBase b (CondT a m) where
+    liftBase m = CondT $ liftM accept' $ liftBase m
+    {-# INLINE liftBase #-}
+
+instance MonadIO m => MonadIO (CondT a m) where
+    liftIO m = CondT $ liftM accept' $ liftIO m
+    {-# INLINE liftIO #-}
+
+instance MonadTrans (CondT a) where
+    lift m = CondT $ liftM accept' $ lift m
+    {-# INLINE lift #-}
+
+#if MIN_VERSION_monad_control(1,0,0)
+instance MonadBaseControl b m => MonadBaseControl b (CondT r m) where
+    type StM (CondT r m) a = StM m (CondR r m a, r)
+    liftBaseWith f = CondT $ StateT $ \s ->
+        liftM (\x -> (accept' x, s)) $ liftBaseWith $ \runInBase ->
+            f $ \k -> runInBase $ runStateT (getCondT k) s
+    {-# INLINABLE liftBaseWith #-}
+    restoreM = CondT . StateT . const . restoreM
+    {-# INLINE restoreM #-}
+#else
+instance MonadBaseControl b m => MonadBaseControl b (CondT r m) where
+    newtype StM (CondT r m) a =
+        CondTStM { unCondTStM :: StM m (Result r m a, r) }
+    liftBaseWith f = CondT $ StateT $ \s ->
+        liftM (\x -> (accept' x, s)) $ liftBaseWith $ \runInBase -> f $ \k ->
+            liftM CondTStM $ runInBase $ runStateT (getCondT k) s
+    {-# INLINEABLE liftBaseWith #-}
+    restoreM = CondT . StateT . const . restoreM . unCondTStM
+    {-# INLINE restoreM #-}
+#endif
+
+instance MFunctor (CondT a) where
+    hoist nat (CondT m) = CondT $ hoist nat (fmap (hoist nat) `liftM` m)
+    {-# INLINE hoist #-}
+
+-- This won't work for StateT-like types
+-- instance MMonad (CondT a) where
+--     embed f m = undefined
+--     {-# INLINE embed #-}
+
+instance MonadCont m => MonadCont (CondT a m) where
+    callCC f = CondT $ StateT $ \a ->
+        callCC $ \k -> flip runStateT a $ getCondT $ f $ \r ->
+            CondT $ StateT $ \a' -> k ((Just r, Continue), a')
+
+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
+    mfix f = CondT $ StateT $ \a -> mdo
+        ((mb, n), a') <- case mb of
+            Nothing -> return ((mb, n), a')
+            Just b  -> runStateT (getCondT (f b)) a
+        return ((mb, n), a')
+
+-- | Apply a condition to an input value, returning a (possibly) updated copy
+-- of that value if it matches, and the next 'CondT' to use if recursion into
+-- that value was indicated.
+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
+{-# INLINE runCondT #-}
+
+runCond :: a -> Cond a r -> Maybe r
+runCond = ((fst . fst . runIdentity) .) . runCondT
+{-# INLINE runCond #-}
+
+execCondT :: Monad m => a -> CondT a m r -> m (Maybe a, Maybe (CondT a m r))
+execCondT a c = go `liftM` runCondT a c
+  where
+    go ((mr, mnext), a') = (const a' <$> mr, mnext)
+{-# INLINE execCondT #-}
+
+evalCondT :: Monad m => a -> CondT a m r -> m (Maybe r)
+evalCondT a c = go `liftM` runCondT a c
+  where
+    go ((mr, _), _) = mr
+{-# INLINE evalCondT #-}
+
+-- | A specialized variant of 'runCondT' that simply returns True or False.
+--
+-- >>> let good = guard_ (== "foo.hs") :: Cond String ()
+-- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()
+-- >>> runIdentity $ test "foo.hs" $ not_ bad >> return "Success"
+-- True
+-- >>> runIdentity $ test "foo.hs" $ not_ good >> return "Shouldn't reach here"
+-- False
+test :: Monad m => a -> CondT a m r -> m Bool
+test a c = go `liftM` runCondT a c
+  where
+    go ((Nothing, _), _) = False
+    go ((Just _, _), _)  = True
+{-# INLINE test #-}
+
+-- | 'MonadQuery' is a custom version of 'MonadReader', created so that users
+-- could still have their own 'MonadReader' accessible within conditionals.
+class Monad m => MonadQuery a m | m -> a where
+    query :: m a
+    queries :: (a -> b) -> m b
+    update :: a -> m ()
+    updates :: (a -> a) -> m ()
+
+instance Monad m => MonadQuery a (CondT a m) where
+    -- | Returns the item currently under consideration.
+    query = CondT $ gets accept'
+    {-# INLINE query #-}
+
+    -- | Returns the item currently under consideration while applying a
+    -- function, in the spirit of 'asks'.
+    queries f = CondT $ state (\a -> (accept' (f a), a))
+    {-# INLINE queries #-}
+
+    update a = CondT $ liftM accept' $ put a
+    {-# INLINE update #-}
+
+    updates f = CondT $ liftM accept' $ modify f
+    {-# INLINE updates #-}
+
+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)
+{-# INLINE guardM #-}
+
+guard_ :: (MonadPlus m, MonadQuery a m) => (a -> Bool) -> m ()
+guard_ f = query >>= guard . f
+{-# INLINE guard_ #-}
+
+guardM_ :: (MonadPlus m, MonadQuery a m) => (a -> m Bool) -> m ()
+guardM_ f = query >>= guardM . f
+{-# INLINE guardM_ #-}
+
+-- | Apply a value-returning predicate. Note that whether or not this return a
+-- 'Just' value, recursion will be performed in the entry itself, if
+-- applicable.
+apply :: (MonadPlus m, MonadQuery a m) => (a -> m (Maybe r)) -> m r
+apply = queries >=> (>>= maybe mzero return)
+{-# INLINE apply #-}
+
+-- | Consider an element, as 'apply', but returning a mutated form of the
+-- element. This can be used to apply optimizations to speed future
+-- conditions.
+consider :: (MonadPlus m, MonadQuery a m) => (a -> m (Maybe (r, a))) -> m r
+consider = queries >=> (>>= maybe mzero (\(r, a') -> const r `liftM` update a'))
+{-# INLINE consider #-}
+
+accept :: MonadPlus m => m ()
+accept = return ()
+{-# INLINE accept #-}
+
+-- | 'ignore' ignores the current entry, but allows recursion into its
+--   descendents.  This is the same as 'empty'.
+ignore :: MonadPlus m => m r
+ignore = mzero
+{-# INLINE ignore #-}
+
+-- | 'norecurse' prevents recursion into the current entry's descendents, but
+--   does not ignore the entry itself.
+norecurse :: Monad m => CondT a m ()
+norecurse = CondT $ return (Just (), Stop)
+{-# INLINE 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 #-}
+
+-- | Return True or False depending on whether the given condition matches or
+--   not.  This differs from simply stating the condition in that it itself
+--   always succeeds.
+--
+-- >>> runCond "foo.hs" $ matches (guard =<< queries (== "foo.hs"))
+-- Just True
+-- >>> runCond "foo.hs" $ matches (guard =<< queries (== "foo.hi"))
+-- Just False
+matches :: MonadPlus m => m r -> m Bool
+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.
+--
+-- >>> let good = guard_ (== "foo.hs") :: Cond String ()
+-- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()
+-- >>> runCond "foo.hs" $ if_ good (return "Success") (return "Failure")
+-- Just "Success"
+-- >>> runCond "foo.hs" $ if_ bad (return "Success") (return "Failure")
+-- Just "Failure"
+if_ :: MonadPlus m => m r -> m s -> m s -> m s
+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.
+--
+-- >>> let good = guard_ (== "foo.hs") :: Cond String ()
+-- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()
+-- >>> runCond "foo.hs" $ when_ good ignore
+-- Nothing
+-- >>> runCond "foo.hs" $ when_ bad ignore
+-- Just ()
+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.
+--
+-- >>> let good = guard_ (== "foo.hs") :: Cond String ()
+-- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()
+-- >>> runCond "foo.hs" $ unless_ bad ignore
+-- Nothing
+-- >>> runCond "foo.hs" $ unless_ good ignore
+-- Just ()
+unless_ :: MonadPlus m => m r -> m s -> m ()
+unless_ c x = if_ c (return ()) (x >> return ())
+{-# INLINE unless_ #-}
+
+-- | Check whether at least one of the given conditions is true.  This is a
+--   synonym for 'Data.Foldable.asum'.
+--
+-- >>> let good = guard_ (== "foo.hs") :: Cond String ()
+-- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()
+-- >>> runCond "foo.hs" $ or_ [bad, good]
+-- Just ()
+-- >>> runCond "foo.hs" $ or_ [bad]
+-- Nothing
+or_ :: MonadPlus m => [m r] -> m r
+or_ = Data.Foldable.msum
+{-# INLINE or_ #-}
+
+-- | Check that all of the given conditions are true.  This is a synonym for
+--   'Data.Foldable.sequence_'.
+--
+-- >>> let good = guard_ (== "foo.hs") :: Cond String ()
+-- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()
+-- >>> runCond "foo.hs" $ and_ [bad, good]
+-- Nothing
+-- >>> runCond "foo.hs" $ and_ [good]
+-- Just ()
+and_ :: MonadPlus m => [m r] -> m ()
+and_ = sequence_
+{-# INLINE and_ #-}
+
+-- | 'not_' inverts the meaning of the given predicate.
+--
+-- >>> let good = guard_ (== "foo.hs") :: Cond String ()
+-- >>> let bad  = guard_ (== "foo.hi") :: Cond String ()
+-- >>> runCond "foo.hs" $ not_ bad >> return "Success"
+-- Just "Success"
+-- >>> runCond "foo.hs" $ not_ good >> return "Shouldn't reach here"
+-- Nothing
+not_ :: MonadPlus m => m r -> m ()
+not_ c = if_ c ignore accept
+{-# INLINE not_ #-}
+
+-- | 'recurse' changes the recursion predicate for any child elements.  For
+--   example, the following file-finding predicate looks for all @*.hs@ files,
+--   but under any @.git@ directory looks only for a file named @config@:
+--
+-- @
+-- if_ (name_ \".git\" \>\> directory)
+--     (ignore \>\> recurse (name_ \"config\"))
+--     (glob \"*.hs\")
+-- @
+--
+-- NOTE: If this code had used @recurse (glob \"*.hs\"))@ instead in the else
+-- case, it would have meant that @.git@ is only looked for at the top-level
+-- of the search (i.e., the top-most element).
+recurse :: Monad m => CondT a m r -> CondT a m r
+recurse c = CondT $ fmap (const (Recurse c)) `liftM` getCondT c
+{-# INLINE recurse #-}
diff --git a/src/Hierarchy.hs b/src/Hierarchy.hs
new file mode 100644
--- /dev/null
+++ b/src/Hierarchy.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module Hierarchy where
+
+import Control.Monad
+import Control.Comonad.Trans.Cofree
+import Control.Cond
+
+-- | A 'TreeT' is a tree of values, where the (possible) branches are
+--   'ListT's over some Monad 'm'.
+type TreeT m = CofreeT Maybe m
+
+-- | Turn a list into a series of possibilities:
+--
+-- >>> observeAllT $ considering [1,2,3]
+-- [1,2,3]
+select :: MonadPlus m => [a] -> m a
+select = msum . map pure
+
+-- | Descend one level into a 'TreeT', yielding a list of values and their
+--   possible associated trees.
+descend :: MonadPlus m => TreeT m a -> m (a, Maybe (TreeT m a))
+descend (CofreeT t) = t >>= \(a :< mp) -> pure (a, mp)
+{-# INLINE descend #-}
+
+-- | Perform a depth-first traversal of a 'TreeT', yielding a 'ListT' of its
+--   contents. Note that breadth-first traversals cannot offer static memory
+--   guarantees, so they are not provided by this module.
+walk :: MonadPlus m => TreeT m a -> m a
+walk (CofreeT t) = t >>= \(a :< mp) -> pure a `mplus` maybe mzero walk mp
+{-# INLINEABLE walk #-}
+
+-- | Given a 'TreeT', produce another 'TreeT' which yields only those elements
+--   (and sub-trees) matching the given monadic conditional. This conditional
+--   (see 'Control.Cond.CondT') can choose both elements and points of
+--   recursion, making it capable of expressing any tree traversal in the form
+--   of a predicate DSL. This differs from an expression-based traversal, like
+--   XPath or Lens, in that effects in 'm' may be used to guide selection.
+--
+--   For example, to print all Haskell files under the current directory:
+--
+-- @
+-- let files = winnow (directoryFiles ".") $ do
+--         path <- query
+--         liftIO $ putStrLn $ "Considering " ++ path
+--         when (path @`elem@` [".@/@.git", ".@/@dist", ".@/@result"])
+--             prune  -- ignore these, and don't recurse into them
+--         guard_ (".hs" @`isInfixOf@`)  -- implicitly references 'path'
+-- runEffect $ for (runListT (walk files)) $ liftIO . print
+-- @
+winnow :: MonadPlus m => TreeT m a -> CondT a m () -> TreeT m a
+winnow (CofreeT t) p = CofreeT $ t >>= \(a :< mst) -> do
+    (mval, mnext) <- execCondT a p
+    let mnext' = winnow <$> mst <*> mnext
+    case mval of
+        Nothing -> maybe mzero runCofreeT mnext'
+        Just a' -> pure $ a' :< mnext'
diff --git a/test/Main.hs b/test/Main.hs
deleted file mode 100644
--- a/test/Main.hs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Main where
-
--- import Control.Cond
--- import Control.Monad
--- import Data.List
--- import Pipes
--- import Pipes.Prelude (toListM)
--- import Pipes.Tree
-import Test.Hspec
--- import Test.Hspec.Expectations
-
-main :: IO ()
-main = hspec $
-    describe "Sanity tests" $
-        it "No tests yet" $ True `shouldBe` True
diff --git a/test/doctest.hs b/test/doctest.hs
--- a/test/doctest.hs
+++ b/test/doctest.hs
@@ -9,15 +9,13 @@
 
 main :: IO ()
 main = getSources >>= \sources -> doctest $
-    "-iControl"
-  : "-iPipes"
+    "-isrc"
   : "-idist/build/autogen"
   : sources
 
 getSources :: IO [FilePath]
 getSources =
-    filter (\n -> ".hs" `isSuffixOf` n) <$>
-        (liftA2 (++) (go "./Control") (go "./Pipes"))
+    filter (\n -> ".hs" `isSuffixOf` n) <$> go "./src"
   where
     go dir = do
       (dirs, files) <- getFilesAndDirectories dir
