hierarchy-0.3.0: Pipes-based library for 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) 
MonadBaseControl b m => MonadBaseControl b (CondT r m) 
MonadError e m => MonadError e (CondT a m) 
MonadReader r m => MonadReader r (CondT a m) 
MonadState s m => MonadState s (CondT a m) 
MonadWriter w m => MonadWriter w (CondT a m) 
Monad m => MonadQuery a (CondT a m) 
MFunctor (CondT a) 
MonadTrans (CondT a) 
(Monad m, Functor m) => Alternative (CondT a m) 
Monad m => Monad (CondT a m) 
Functor m => Functor (CondT a m) 
MonadFix m => MonadFix (CondT a m) 
Monad m => MonadPlus (CondT a m) 
(Monad m, Functor m) => Applicative (CondT a m) 
Monad m => MonadZip (CondT a m) 
MonadThrow m => MonadThrow (CondT a m) 
MonadCatch m => MonadCatch (CondT a m) 
MonadMask m => MonadMask (CondT a m) 
MonadIO m => MonadIO (CondT a m) 
MonadCont m => MonadCont (CondT a m) 
(Monad m, Monoid r) => Monoid (CondT a m r) 
(Monad m, Semigroup r) => Semigroup (CondT a m r) 
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.

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) 
MonadQuery r m => MonadQuery r (ListT m) 
MonadQuery r m => MonadQuery r (IdentityT m) 
(Monoid w, MonadQuery r m) => MonadQuery r (WriterT w m) 
(Monoid w, MonadQuery r m) => MonadQuery r (WriterT w m) 
MonadQuery r m => MonadQuery r (StateT s m) 
MonadQuery r m => MonadQuery r (StateT s m) 
MonadQuery r m => MonadQuery r (ExceptT e m) 
(Error e, MonadQuery r m) => MonadQuery r (ErrorT e m) 
MonadQuery r' m => MonadQuery r' (ContT r m) 
MonadQuery r m => MonadQuery r (ReaderT r m) 
Monad m => MonadQuery a (CondT a m) 
(MonadQuery r m, Monoid w) => MonadQuery r (RWST r w s m) 
(MonadQuery r m, Monoid w) => MonadQuery r (RWST r w s m) 

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. It is the same as ignore >> norecurse.

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

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