I'm trying to convert IO [String]
to [String]
with <-
binding; however, I need to use a do
block to do that under a where
statement, but Haskell complains about the indentation all the time. Here is the code:
decompEventBlocks :: IO [String] -> IO [[String]]
decompEventBlocks words
| words' /= [] = block : (decompEventBlocks . drop $ (length block) words')
| otherwise = []
where
do
words' <- words
let block = (takeWhile (/="END") words')
What is the reason for that ? And how can we use do
block in a where
statement ? Moreover, is there any chance that we can have some statements before the guards ?
Remember: do
-blocks are syntactic sugar for monadic notation. This means the following applies:
do {a; b} = a >> b
dp {a <- b; c} = b >>= \a -> c
In other words, when using do
-notation, you are actually producing values. This is why you can't just have a do
-block in the top level of your where
statement.
The way to solve this is to put the function into a do
-block:
decompEventBlocks :: IO [String] -> IO [[String]]
decompEventBlocks words = do
-- We unwrap the IO [String], but we keep it in the do-block,
-- because it must be kept in a monadic context!
words' <- words
let block = (takeWhile (/="END") words')
-- This is equivalent to the guards you had in your function.
-- NB return :: Monad m => a -> m a, to keep it in a monadic context!
if not $ null words'
then do
-- Since the recursion is monadic, we must bind it too:
rest <- decompEventBlocks $ return $ drop (length block) words'
return $ block : rest
else return []
To learn about monads, do
-notation, >>=
, and >>
, I highly reccommend reading the LYAH chapters to gain a good understanding before attempting more monadic code.