1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
{-# LANGUAGE NoMonomorphismRestriction #-}
-- | Library for control flow inside of monads with anaphoric variants on if and when and a C-like \"switch\" function.
--
-- Information:
--
-- [@Author@] Jeff Heard
--
-- [@Copyright@] 2008 Jeff Heard
--
-- [@License@] BSD
--
-- [@Version@] 1.0
--
-- [@Status@] Alpha
module Control.Monad.IfElse where
import Control.Monad
-- A if with no else for unit returning thunks.
-- Returns the value of the test.
-- when :: Monad m => Bool -> m () -> m Bool
-- when True action = action >> return True
-- when False _ = return False
-- | A if with no else for unit returning thunks.
-- Returns the value of the test.
whenM :: Monad m => m Bool -> m () -> m ()
whenM test action = test >>= \t -> if t then action else return ()
-- | Like a switch statement, and less cluttered than if else if
--
-- > cond [ (t1,a1), (t2,a2), ... ]
cond :: Monad m => [(Bool, m ())] -> m ()
cond [] = return ()
cond ((True,action) : _) = action
cond ((False,_) : rest) = cond rest
-- | Like a switch statement, and less cluttered than if else if
--
-- > condM [ (t1,a1), (t2,a2), ... ]
condM :: Monad m => [(m Bool, m ())] -> m ()
condM [] = return ()
condM ((test,action) : rest) = test >>= \t -> if t then action else condM rest
-- | Chainable anaphoric when. Takes a maybe value.
--
-- if the value is Just x then execute @ action x @ , then return @ True @ . otherwise return @ False @ .
awhen :: Monad m => Maybe a -> (a -> m ()) -> m ()
awhen Nothing _ = return ()
awhen (Just x) action = action x
-- | Chainable anaphoric whenM.
awhenM :: Monad m => m (Maybe a) -> (a -> m ()) -> m ()
awhenM test action = test >>= \t -> case t of
Just x -> action x
Nothing -> return ()
-- | Anaphoric when-else chain. Like a switch statement, but less cluttered
acond :: Monad m => [(Maybe a, a -> m ())] -> m ()
acond ((Nothing,_) : rest) = acond rest
acond ((Just x, action) : _) = action x
acond [] = return ()
-- | Anaphoric if.
aif :: Monad m => Maybe a -> (a -> m b) -> m b -> m b
aif Nothing _ elseclause = elseclause
aif (Just x) ifclause _ = ifclause x
-- | Anaphoric if where the test is in Monad m.
aifM :: Monad m => m (Maybe a) -> (a -> m b) -> m b -> m b
aifM test ifclause elseclause = test >>= \t -> aif t ifclause elseclause
-- | Contrapositive of whenM, if not x then do y
unlessM a = whenM (liftM not $ a)
-- | unless-else chain.
ncond [] = return ()
ncond ((test , action) : rest) = if not test then action else ncond rest
-- | monadic unless-else chain
ncondM :: Monad m => [(m Bool, m ())] -> m ()
ncondM [] = return ()
ncondM ((test , action) : rest) = test >>= \t -> if not t then action else ncondM rest
-- | IO lifted @ && @
(&&^) = liftM2 (&&)
-- | IO lifted @ || @
(||^) = liftM2 (||)
-- | Conditionally do the right action based on the truth value of the left expression
(>>?) = when
infixl 1 >>?
-- | unless the left side is true, perform the right action
(>>!) = unless
infixl 1 >>!
-- | unless the (monadic) left side is true, perform the right action
(>>=>>!) = unlessM
infixl 1 >>=>>!
-- | Bind the result of the last expression in an anaphoric when.
(>>=?) = awhen
infixl 1 >>=?
-- | composition of @ >>= @ and @ >>? @
(>>=>>?) = whenM
infixl 1 >>=>>?
-- | composition of @ >>= @ and @ >>=? @
(>>=>>=?) = awhenM
infixl 1 >>=>>=?
--
-- The following is from Control.Monad.Extras by Wren Thornton.
--
-- | Execute a monadic action so long as a monadic boolean returns
-- true.
{-# SPECIALIZE whileM :: IO Bool -> IO () -> IO () #-}
whileM :: (Monad m) => m Bool -> m () -> m ()
whileM mb m = do b <- mb ; when b (m >> whileM mb m)
-- Named with M because 'Prelude.until' exists
-- | Negation of 'whileM': execute an action so long as the boolean
-- returns false.
{-# SPECIALIZE untilM :: IO Bool -> IO () -> IO () #-}
untilM :: (Monad m) => m Bool -> m () -> m ()
untilM mb m = do b <- mb ; unless b (m >> untilM mb m)
-- | Strict version of 'return' because usually we don't need that
-- extra thunk.
{-# INLINE return' #-}
return' :: (Monad m) => a -> m a
return' x = return $! x
-- | Take an action and make it into a side-effecting 'return'.
-- Because I seem to keep running into @m ()@ and the like.
infixr 8 `returning`
{-# INLINE returning #-}
returning :: (Monad m) => (a -> m b) -> (a -> m a)
f `returning` x = f x >> return x
-- For reference this is also helpful:
-- > liftM2 (>>) f g == \x -> f x >> g x
-- | This conversion is common enough to make a name for.
{-# INLINE maybeMP #-}
maybeMP :: (MonadPlus m) => Maybe a -> m a
maybeMP = maybe mzero return
-- This rule should only fire when type-safe
{-# RULES "maybeMP/id" maybeMP = id #-}
|