I've found that I don't know how to handle nested if-else-then
in do
-blocks in Haskell.
I know already that I can use a case
, but that would require all my conditions (a
, b
and c
) to return the same type (Bool
, so there are only two cases, but I need three distinct ones) and is therefore not as general (correct me if I'm wrong). I have also tried considering using guards here, but I don't know how to make this work in a do
statement, especially if the -- something
expressions are meant to be of type IO ()
.
Suppose I have the following code that is inside a do
:
if a then
-- something
else
if b then
-- something
else
if c then
-- something
else
-- something
How do I create the equivalent logic but without all the indenting?
To begin with, it is worth noting that if-expressions do not actually require extra indentation (if-within-do used to be an exception, but Haskell 2010 eliminated that). That means you might collapse all the extra indentation:
test = do
len <- length <$> getLine
if len < 4
then putStrLn "Short"
else if len > 6
then putStrLn "Long"
else putStrLn "Mid"
Personally, though, I don't find that too pleasing aesthetically, as I feel some indentation makes if-expressions easier to follow. A nice alternative is using the MultiWayIf
extension:
{-# LANGUAGE MultiWayIf #-}
test = do
len <- length <$> getLine
if | len < 4 -> putStrLn "Short"
| len > 6 -> putStrLn "Long"
| otherwise -> putStrLn "Mid"
On a final note, nested if-expressions getting unwieldy might reveal a good occasion for breaking things down in separate definitions, or otherwise reorganising your code. See also: How do I deal with many levels of indentation?
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