Haskell : non-symmetric nested do-notation and let
Solution 1:
The two branches of an if
must have the same type. If you need one with a monadic type and the other with a "pure" type, you need to make those types equal using a return
(or, equivalently, pure
).
Here's an example using the IO monad. You can adapt it to your case.
main :: IO ()
main = do
putStrLn "enter True of False"
x <- readLn
res <- if x
then do
putStrLn "You entered True: write somehting now"
getLine -- its result is bound to res
else return "nothing" -- res is bound to "nothing"
putStrLn $ "final result: " ++ res
Main points:
- If a branch of your
if
contains an action that you want to run right now, you must avoidlet res = if ...
and instead useres <- if ...
. The former definesres
to be the action itself, the latter executes the action and definesres
to be the result produced by the action. - Both braches of
res <- if ...
must have the same monadic type. Usereturn
to make it so.
There is no way to use the standard if
with a monadic then branch and a non-monadic else branch. At best, we can define a custom "if" function that does that, e.g.
ifMon :: Monad m => Bool -> m a -> a -> m a
ifMon True x _ = x
ifMon False _ y = return y
This can be used as
do
putStrLn "blah"
res <- ifMon condition
(do
putStrLn "then branch"
return "abc")
"else result, non monadic"
You can have a similar helper function for the case where the then branch is "pure" and the else branch is monadic.