I’m reading in several lines from the input that the user has to type:
main :: IO ()
main = do
let size = 3
arr <- replicateM size getLine
let pairs = map parsePair arr
print pairs
Why am I allowed to do map parsePair arr
on a separate line
but not on the same line, like this:
arr <- map parsePair (replicateM size getLine)
Doing so, I get the error :
• Couldn't match type ‘[]’ with ‘IO’
Expected type: IO [Int]
Actual type: [[Int]]
To give you more details, here is parsePair
:
parsePair string = map parseInt $ words string
parseInt :: String -> Int
parseInt s = read s :: Int
Because the type of replicateM size getLine
is IO [String]
, it is not a list of String
s, it is basically a description of an IO
action that will obtain a [String]
. You can see the arrow <-
in an IO
monad as a way to retrieve it and unpack the result.
You can however do some processing on that like, since IO
is a Functor
as well, you can make use of fmap :: Functor f => (a -> b) -> f a -> f b
:
main :: IO [Int]
main = do
let size = 3
fmap (map parsePair) (replicateM size getLine)
or you can shift the fmap
to the getLine
part:
main :: IO [Int]
main = do
let size = 3
replicateM size (fmap parsePair getLine)
Note that there is a readLn :: Read a => IO a
function that is basically fmap read getLine
(except that it does some addional error handling). We can thus use:
main :: IO [Int]
main = do
let size = 3
replicateM size readLn