module Control.Monad.Tools (
  ifM
, whenM
, unlessM
, doWhile_
, doWhile
, for_
, for
, skipRet
) where

import Control.Monad         (when, unless)

ifM :: Monad m => m Bool -> m a -> m a -> m a
ifM p t e = do b <- p
               if b then t else e

whenM, unlessM :: Monad m => m Bool -> m () -> m ()
whenM p t   = p >>= flip when t
unlessM p e = p >>= flip unless e

doWhile_ :: Monad m => m Bool -> m ()
doWhile_ act = do p <- act
                  when p $ doWhile_ act

doWhile :: Monad m => a -> (a -> m (a, Bool)) -> m a
doWhile i act = do (r, p) <- act i
                   if p then doWhile r act
		        else return r

for_ :: Monad m => a -> (a -> Bool) -> (a -> a) -> (a -> m b) -> m ()
for_ i test next act
  | test i    = act i >> for_ (next i) test next act
  | otherwise = return ()

for :: Monad m => a -> (a -> Bool) -> (a -> a) -> b -> (a -> b -> m b) -> m b
for i test next j act
  | test i    = act i j >>= flip (for (next i) test next) act
  | otherwise = return j

skipRet :: Monad m => m b -> a -> m a
skipRet p x = p >> return x