I was making a program with Haskell and it's IO, when I came across an error I don't understand. When I use a where statement after a do block it does not do the same thing as without the do block.
The program that works is:
import Control.Monad
prog :: IO()
prog = do m <- getLine
n <- getLine
p <- getLine
replicateM_ (read m :: Int) (putStrLn n)
replicateM_ (read m :: Int) (putStrLn p)
But when I replace the read m :: Int with a where statement like this:
import Control.Monad
prog1 :: IO()
prog1 = do m <- getLine
n <- getLine
p <- getLine
replicateM_ (a) (putStrLn n)
replicateM_ (a) (putStrLn p)
where
a = read m :: Int
I get the error:
Template.hs:23:21: error: Variable not in scope: m :: String
|
23 | a = read m :: Int
| ^
I have looked what the problem could be, and I think it has to do with the type of m, which is IO String. I know you have to stay in the IO type (once you are in it) to be able to work with the string. But I don't understand why the 'where' would "break out" of this IO type. To my understanding the two examples I gave are functional the same. First I thought that the error wouldn't be fixed by writing the program without the where, because the function read is from the type read :: Read a => String -> a and my input in the first program is also IO String. So why didn't my first program give me an error? Could someone explain what I understand wrong and how I can fix my program so I only have to execute read m :: Int once? Just some tips of how to use a where statement under a do block would also help.
The original program I got the problem in is longer and not all relevant so I used this minimal working example to explain the essence of my question. In my original program I have multiple statements after where, so I don't want to substitute it all like I did in this example.