Been scratching my head for a day over this one.
I have a few functions in my code that look like this:
function :: IO (Maybe Whatever)
function = do
monadFun
yaySomeIO
status <- maybeItWillFail
if checkStatus status -- Did we succeed?
then monadTime >>= return . Just . processItPurely
else return Nothing
ghci will load and run this interactively with no problems, and ghc will compile it happily. Running this through cabal, however, gives me this:
myProgram.hs:94:16:
Unexpected semi-colons in conditional:
if checkStatus status; then monadTime >>= return . Just . processItPurely; else return Nothing
Perhaps you meant to use -XDoAndIfThenElse?
And whatever this -XDoAndIfThenElse
option is, I can't seem to find a trace of it anywhere in any documentation.
Why is cabal (or is this ghc by this point?) yelling at me for using semi-colons that IT put there in the first place? Or is using monadic expressions in if-then-else statements just a bad idea?
Note that cabal doesn't complain about this at all:
case checkStatus status of
True -> monadTime >>= return . Just . processItPurely
_ -> return Nothing
...except this is ugly as hell and I'd never want to put this in my code. Can anyone tell me what's going on? Please and thanks in advance.
The "correct" way of indenting if
-expressions in a do
-block is to indent the else
and then
lines further than the if
, like this.
function = do
monadFun
yaySomeIO
status <- maybeItWillFail
if checkStatus status -- Did we succeed?
then monadTime >>= return . Just . processItPurely
else return Nothing
This is because lines with the same amount of indentation in a do
block are normally treated as separate statements.
However, there is an extension called DoAndIfThenElse
which will allow you to write it the way you did. This extension was made standard in Haskell 2010, which is why GHC enables it by default.
Cabal tends to require you to be more explicit about these things, so to use it in Cabal, you need to either mention it in your .cabal
file or add {-# LANGUAGE DoAndIfThenElse #-}
to the top of your module.
This isn't a direct answer to your question, but you can eliminate the if statement by taking advantage ofMaybeT
. Also, foo >>= return . bar
is the same as bar <$> foo
. (<$>
is from Control.Applicative
, and is the same as fmap
)
function :: MaybeT IO Whatever
function = do
lift monadFun
lift yaySomeIO
status <- lift maybeItWillFail
guard (checkStatus status)
processItPurely <$> lift monadTime
The only annoyance is the gratuitous sprinkling of lift
s, but there are ways to get rid of those.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With