Safe Haskell | None |
---|---|

Language | Haskell2010 |

- data CondT a m r
- type Cond a = CondT a Identity
- runCondT :: Monad m => a -> CondT a m r -> m ((Maybe r, Maybe (CondT a m r)), a)
- runCond :: a -> Cond a r -> Maybe r
- execCondT :: Monad m => a -> CondT a m r -> m (Maybe a, Maybe (CondT a m r))
- evalCondT :: Monad m => a -> CondT a m r -> m (Maybe r)
- test :: Monad m => a -> CondT a m r -> m Bool
- class Monad m => MonadQuery a m | m -> a where
- guardM :: MonadPlus m => m Bool -> m ()
- guard_ :: (MonadPlus m, MonadQuery a m) => (a -> Bool) -> m ()
- guardM_ :: (MonadPlus m, MonadQuery a m) => (a -> m Bool) -> m ()
- apply :: (MonadPlus m, MonadQuery a m) => (a -> m (Maybe r)) -> m r
- consider :: (MonadPlus m, MonadQuery a m) => (a -> m (Maybe (r, a))) -> m r
- accept :: MonadPlus m => m ()
- ignore :: MonadPlus m => m r
- norecurse :: Monad m => CondT a m ()
- prune :: Monad m => CondT a m r
- matches :: MonadPlus m => m r -> m Bool
- ifM :: Monad m => m Bool -> m s -> m s -> m s
- whenM :: Monad m => m Bool -> m s -> m ()
- unlessM :: Monad m => m Bool -> m s -> m ()
- if_ :: MonadPlus m => m r -> m s -> m s -> m s
- when_ :: MonadPlus m => m r -> m s -> m ()
- unless_ :: MonadPlus m => m r -> m s -> m ()
- or_ :: MonadPlus m => [m r] -> m r
- and_ :: MonadPlus m => [m r] -> m ()
- not_ :: MonadPlus m => m r -> m ()
- recurse :: Monad m => CondT a m r -> CondT a m r

# Documentation

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

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

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

`>>>`

True`runIdentity $ test "foo.hs" $ not_ bad >> return "Success"`

`>>>`

False`runIdentity $ test "foo.hs" $ not_ good >> return "Shouldn't reach here"`

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

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

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

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

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

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

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

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

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

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

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

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

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

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

(MonadQuery r m, Monoid w) => MonadQuery r (RWST r w s 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

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.

`>>>`

Just True`runCond "foo.hs" $ matches (guard =<< queries (== "foo.hs"))`

`>>>`

Just False`runCond "foo.hs" $ matches (guard =<< queries (== "foo.hi"))`

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

`>>>`

Just "Success"`runCond "foo.hs" $ if_ good (return "Success") (return "Failure")`

`>>>`

Just "Failure"`runCond "foo.hs" $ if_ bad (return "Success") (return "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 ()`

`>>>`

Nothing`runCond "foo.hs" $ when_ good ignore`

`>>>`

Just ()`runCond "foo.hs" $ when_ bad ignore`

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

`>>>`

Nothing`runCond "foo.hs" $ unless_ bad ignore`

`>>>`

Just ()`runCond "foo.hs" $ unless_ good ignore`

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

`>>>`

Just ()`runCond "foo.hs" $ or_ [bad, good]`

`>>>`

Nothing`runCond "foo.hs" $ or_ [bad]`

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

`>>>`

Nothing`runCond "foo.hs" $ and_ [bad, good]`

`>>>`

Just ()`runCond "foo.hs" $ and_ [good]`

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

`>>>`

Just "Success"`runCond "foo.hs" $ not_ bad >> return "Success"`

`>>>`

Nothing`runCond "foo.hs" $ not_ good >> return "Shouldn't reach here"`

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