in my program I use a function if'
defined in one of the modules instead of the built-in if-then-else
construct. It is defined trivially and works just fine.
However, there's one place in code where I need to apply it to monad values (IO
in my case), i.e. the type signature should look somewhat like IO Bool -> IO a -> IO a -> IO a
.
Naturally, I tried to lift it.
if' <$> mb <*> action1 <*> action2
But when I try to evaluate the expression, I don't get what I expect.
*Main> if' <$> return True <*> putStrLn "yes" <*> putStrLn "no"
yes
no
I know that <*>
description reads „sequential application“, so maybe it's that. But what is happening here? Can I fix it without writing a whole new dedicated function?
(<*>)
evaluates both of its arguments, so it effectively a pipeline of applications lifted over some applicative. The ability to inspect values and change the future of the computation is the extra power that the Monad
class has over Applicative
so you need to use that instead e.g.
mif' :: Monad m => m Bool -> m a -> m a -> m a
mif' bm xm ym = bm >>= (\b -> if b then xm else ym)