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 ?
Do notation is used to write expressions of the general form
Notice all the
m
s are the same, anda
,b
,c
, ... can be different, though thet
in the last do sub-expression's type and the overall do expression's type is the same.The do notation variables are said to be "bound" by the
<-
construct. They come into scope at their introduction (to the left of<-
) and remain in scope for all the subsequent do sub-expressions.One built-in monadic expression available for any monad is
return :: Monad m => a -> m a
. Thusx <- return v
bindsx
tov
, so thatx
will be available in the subsequent sub-expressions, and will have the value ofv
.All the do variables are confined to that
do
block, and can not be used outside it. Each variable's scope is all the code in the samedo
block, below / after the variable's binding.This also means that
<-
's is a non-recursive binding, since the variable can't go on its right hand side as well as the left: it will be two different variables with the same name, in that case, and the variable on the right will have to have been established somewhere above that point.There are a few general patterns here:
All the
Monad m => m a
expressions are just that, expressions, and so can in particular be anif - then - else
expressions with both the consequent and the alternative branches being of the same monadic type (which is often confusing for beginners):update: One of the main points of the monad is its total separation of effects from the pure calculations. Once in a monad, you can't "get out". Monadic computations can use pure calculations, but not vice versa.
You cannot convert for IO String to a String.
What you can do, however, is bind the contents of IO String to a 'variable', but that will still result in the whole computation being embedded inside IO.
To answer your question
Remember:
do
-blocks are syntactic sugar for monadic notation. This means the following applies:In other words, when using
do
-notation, you are actually producing values. This is why you can't just have ado
-block in the top level of yourwhere
statement.The way to solve this is to put the function into a
do
-block:To learn about monads,
do
-notation,>>=
, and>>
, I highly reccommend reading the LYAH chapters to gain a good understanding before attempting more monadic code.As a slightly different angle on AJFarmar's answer: The only things you can have in a
where
are declarations.do
blocks aren't declarations, they are expressions. I.e. this is the same as if you tried to writewhere 2+5
. If you want to declareblock
in awhere
, it must be