hierarchy-1.0.1: Predicated traversal of generated trees

Safe HaskellNone
LanguageHaskell2010

Control.Cond

Contents

Synopsis

Documentation

data CondT a m r Source #

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.

Instances

MonadBase b m => MonadBase b (CondT a m) Source # 

Methods

liftBase :: b α -> CondT a m α #

MonadBaseControl b m => MonadBaseControl b (CondT r m) Source # 

Associated Types

type StM (CondT r m :: * -> *) a :: * #

Methods

liftBaseWith :: (RunInBase (CondT r m) b -> b a) -> CondT r m a #

restoreM :: StM (CondT r m) a -> CondT r m a #

MonadWriter w m => MonadWriter w (CondT a m) Source # 

Methods

writer :: (a, w) -> CondT a m a #

tell :: w -> CondT a m () #

listen :: CondT a m a -> CondT a m (a, w) #

pass :: CondT a m (a, w -> w) -> CondT a m a #

MonadState s m => MonadState s (CondT a m) Source # 

Methods

get :: CondT a m s #

put :: s -> CondT a m () #

state :: (s -> (a, s)) -> CondT a m a #

MonadReader r m => MonadReader r (CondT a m) Source # 

Methods

ask :: CondT a m r #

local :: (r -> r) -> CondT a m a -> CondT a m a #

reader :: (r -> a) -> CondT a m a #

MonadError e m => MonadError e (CondT a m) Source # 

Methods

throwError :: e -> CondT a m a #

catchError :: CondT a m a -> (e -> CondT a m a) -> CondT a m a #

Monad m => MonadQuery a (CondT a m) Source # 

Methods

query :: CondT a m a Source #

queries :: (a -> b) -> CondT a m b Source #

update :: a -> CondT a m () Source #

updates :: (a -> a) -> CondT a m () Source #

MonadTrans (CondT a) Source # 

Methods

lift :: Monad m => m a -> CondT a m a #

MFunctor * (CondT a) Source # 

Methods

hoist :: Monad m => (forall b. m b -> n b) -> t m b -> t n b #

Monad m => Monad (CondT a m) Source # 

Methods

(>>=) :: CondT a m a -> (a -> CondT a m b) -> CondT a m b #

(>>) :: CondT a m a -> CondT a m b -> CondT a m b #

return :: a -> CondT a m a #

fail :: String -> CondT a m a #

Functor m => Functor (CondT a m) Source # 

Methods

fmap :: (a -> b) -> CondT a m a -> CondT a m b #

(<$) :: a -> CondT a m b -> CondT a m a #

MonadFix m => MonadFix (CondT a m) Source # 

Methods

mfix :: (a -> CondT a m a) -> CondT a m a #

Monad m => Applicative (CondT a m) Source # 

Methods

pure :: a -> CondT a m a #

(<*>) :: CondT a m (a -> b) -> CondT a m a -> CondT a m b #

liftA2 :: (a -> b -> c) -> CondT a m a -> CondT a m b -> CondT a m c #

(*>) :: CondT a m a -> CondT a m b -> CondT a m b #

(<*) :: CondT a m a -> CondT a m b -> CondT a m a #

Monad m => MonadZip (CondT a m) Source # 

Methods

mzip :: CondT a m a -> CondT a m b -> CondT a m (a, b) #

mzipWith :: (a -> b -> c) -> CondT a m a -> CondT a m b -> CondT a m c #

munzip :: CondT a m (a, b) -> (CondT a m a, CondT a m b) #

MonadIO m => MonadIO (CondT a m) Source # 

Methods

liftIO :: IO a -> CondT a m a #

Monad m => Alternative (CondT a m) Source # 

Methods

empty :: CondT a m a #

(<|>) :: CondT a m a -> CondT a m a -> CondT a m a #

some :: CondT a m a -> CondT a m [a] #

many :: CondT a m a -> CondT a m [a] #

Monad m => MonadPlus (CondT a m) Source # 

Methods

mzero :: CondT a m a #

mplus :: CondT a m a -> CondT a m a -> CondT a m a #

MonadThrow m => MonadThrow (CondT a m) Source # 

Methods

throwM :: Exception e => e -> CondT a m a #

MonadCatch m => MonadCatch (CondT a m) Source # 

Methods

catch :: Exception e => CondT a m a -> (e -> CondT a m a) -> CondT a m a #

MonadMask m => MonadMask (CondT a m) Source # 

Methods

mask :: ((forall b. CondT a m b -> CondT a m b) -> CondT a m b) -> CondT a m b #

uninterruptibleMask :: ((forall b. CondT a m b -> CondT a m b) -> CondT a m b) -> CondT a m b #

MonadCont m => MonadCont (CondT a m) Source # 

Methods

callCC :: ((a -> CondT a m b) -> CondT a m a) -> CondT a m a #

(Monad m, Semigroup r) => Semigroup (CondT a m r) Source # 

Methods

(<>) :: CondT a m r -> CondT a m r -> CondT a m r #

sconcat :: NonEmpty (CondT a m r) -> CondT a m r #

stimes :: Integral b => b -> CondT a m r -> CondT a m r #

(Monad m, Monoid r) => Monoid (CondT a m r) Source # 

Methods

mempty :: CondT a m r #

mappend :: CondT a m r -> CondT a m r -> CondT a m r #

mconcat :: [CondT a m r] -> CondT a m r #

type StM (CondT r m) a Source # 
type StM (CondT r m) a

Executing CondT

runCondT :: Monad m => a -> CondT a m r -> m ((Maybe r, Maybe (CondT a m r)), a) Source #

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.

runCond :: a -> Cond a r -> Maybe r Source #

execCondT :: Monad m => a -> CondT a m r -> m (Maybe a, Maybe (CondT a m r)) Source #

evalCondT :: Monad m => a -> CondT a m r -> m (Maybe r) Source #

test :: Monad m => a -> CondT a m r -> m Bool Source #

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

Promotions

class Monad m => MonadQuery a m | m -> a where Source #

MonadQuery is a custom version of MonadReader, created so that users could still have their own MonadReader accessible within conditionals.

Minimal complete definition

query, queries, update, updates

Methods

query :: m a Source #

queries :: (a -> b) -> m b Source #

update :: a -> m () Source #

updates :: (a -> a) -> m () Source #

Instances

MonadQuery r m => MonadQuery r (MaybeT m) Source # 

Methods

query :: MaybeT m r Source #

queries :: (r -> b) -> MaybeT m b Source #

update :: r -> MaybeT m () Source #

updates :: (r -> r) -> MaybeT m () Source #

MonadQuery r m => MonadQuery r (ListT m) Source # 

Methods

query :: ListT m r Source #

queries :: (r -> b) -> ListT m b Source #

update :: r -> ListT m () Source #

updates :: (r -> r) -> ListT m () Source #

(Monoid w, MonadQuery r m) => MonadQuery r (WriterT w m) Source # 

Methods

query :: WriterT w m r Source #

queries :: (r -> b) -> WriterT w m b Source #

update :: r -> WriterT w m () Source #

updates :: (r -> r) -> WriterT w m () Source #

(Monoid w, MonadQuery r m) => MonadQuery r (WriterT w m) Source # 

Methods

query :: WriterT w m r Source #

queries :: (r -> b) -> WriterT w m b Source #

update :: r -> WriterT w m () Source #

updates :: (r -> r) -> WriterT w m () Source #

MonadQuery r m => MonadQuery r (StateT s m) Source # 

Methods

query :: StateT s m r Source #

queries :: (r -> b) -> StateT s m b Source #

update :: r -> StateT s m () Source #

updates :: (r -> r) -> StateT s m () Source #

MonadQuery r m => MonadQuery r (StateT s m) Source # 

Methods

query :: StateT s m r Source #

queries :: (r -> b) -> StateT s m b Source #

update :: r -> StateT s m () Source #

updates :: (r -> r) -> StateT s m () Source #

MonadQuery r m => MonadQuery r (IdentityT * m) Source # 

Methods

query :: IdentityT * m r Source #

queries :: (r -> b) -> IdentityT * m b Source #

update :: r -> IdentityT * m () Source #

updates :: (r -> r) -> IdentityT * m () Source #

MonadQuery r m => MonadQuery r (ExceptT e m) Source # 

Methods

query :: ExceptT e m r Source #

queries :: (r -> b) -> ExceptT e m b Source #

update :: r -> ExceptT e m () Source #

updates :: (r -> r) -> ExceptT e m () Source #

(Error e, MonadQuery r m) => MonadQuery r (ErrorT e m) Source # 

Methods

query :: ErrorT e m r Source #

queries :: (r -> b) -> ErrorT e m b Source #

update :: r -> ErrorT e m () Source #

updates :: (r -> r) -> ErrorT e m () Source #

Monad m => MonadQuery a (CondT a m) Source # 

Methods

query :: CondT a m a Source #

queries :: (a -> b) -> CondT a m b Source #

update :: a -> CondT a m () Source #

updates :: (a -> a) -> CondT a m () Source #

MonadQuery r' m => MonadQuery r' (ContT * r m) Source # 

Methods

query :: ContT * r m r' Source #

queries :: (r' -> b) -> ContT * r m b Source #

update :: r' -> ContT * r m () Source #

updates :: (r' -> r') -> ContT * r m () Source #

MonadQuery r m => MonadQuery r (ReaderT * r m) Source # 

Methods

query :: ReaderT * r m r Source #

queries :: (r -> b) -> ReaderT * r m b Source #

update :: r -> ReaderT * r m () Source #

updates :: (r -> r) -> ReaderT * r m () Source #

(MonadQuery r m, Monoid w) => MonadQuery r (RWST r w s m) Source # 

Methods

query :: RWST r w s m r Source #

queries :: (r -> b) -> RWST r w s m b Source #

update :: r -> RWST r w s m () Source #

updates :: (r -> r) -> RWST r w s m () Source #

(MonadQuery r m, Monoid w) => MonadQuery r (RWST r w s m) Source # 

Methods

query :: RWST r w s m r Source #

queries :: (r -> b) -> RWST r w s m b Source #

update :: r -> RWST r w s m () Source #

updates :: (r -> r) -> RWST r w s m () Source #

guardM :: MonadPlus m => m Bool -> m () Source #

guard_ :: (MonadPlus m, MonadQuery a m) => (a -> Bool) -> m () Source #

guardM_ :: (MonadPlus m, MonadQuery a m) => (a -> m Bool) -> m () Source #

apply :: (MonadPlus m, MonadQuery a m) => (a -> m (Maybe r)) -> m r Source #

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.

consider :: (MonadPlus m, MonadQuery a m) => (a -> m (Maybe (r, a))) -> m r Source #

Consider an element, as apply, but returning a mutated form of the element. This can be used to apply optimizations to speed future conditions.

Basic conditionals

accept :: MonadPlus m => m () Source #

ignore :: MonadPlus m => m r Source #

ignore ignores the current entry, but allows recursion into its descendents. This is the same as empty.

norecurse :: Monad m => CondT a m () Source #

norecurse prevents recursion into the current entry's descendents, but does not ignore the entry itself.

prune :: Monad m => CondT a m r Source #

prune is a synonym for both ignoring an entry and its descendents.

Boolean logic

matches :: MonadPlus m => m r -> m Bool Source #

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

ifM :: Monad m => m Bool -> m s -> m s -> m s Source #

whenM :: Monad m => m Bool -> m s -> m () Source #

unlessM :: Monad m => m Bool -> m s -> m () Source #

if_ :: MonadPlus m => m r -> m s -> m s -> m s Source #

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"

when_ :: MonadPlus m => m r -> m s -> m () Source #

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 ()

unless_ :: MonadPlus m => m r -> m s -> m () Source #

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 ()

or_ :: MonadPlus m => [m r] -> m r Source #

Check whether at least one of the given conditions is true. This is a synonym for 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

and_ :: MonadPlus m => [m r] -> m () Source #

Check that all of the given conditions are true. This is a synonym for 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 ()

not_ :: MonadPlus m => m r -> m () Source #

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

helper functions

recurse :: Monad m => CondT a m r -> CondT a m r Source #

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).