Take the function getLine.
it has a type
getLine :: IO String
How do I extract the String from this IO value. More generally, how do I
In Haskell, when you want to work with a value that is "trapped" in IO
, you don't take the value out of IO
. Instead, you put the operation you want to perform into IO
, as well!
For example, suppose you want to check how many characters the getLine :: IO String
will produce, using the length
function from Prelude.
There exists a helper function called fmap which, when specialized to IO
, has the type:
fmap :: (a -> b) -> IO a -> IO b
It takes a function that works on "pure" values not trapped in IO
, and gives you a function that works with values that are trapped in IO
. This means that the code
fmap length getLine :: IO Int
represents an IO
action that reads a line from console and then gives you its length.
<$>
is an infix synonym for fmap
that can make things simpler. This is equivalent to the above code:
length <$> getLine
Now, sometimes the operation you want to perform with the IO
-trapped value itself returns an IO
-trapped value. Simple example: you wan to write back the string you have just read using putStrLn :: String -> IO ()
.
In that case, fmap
is not enough. You need to use the (>>=) operator, which, when specialiced to IO
, has the type IO a -> (a -> IO b) -> IO b
. In out case:
getLine >>= putStrLn :: IO ()
Using (>>=)
to chain IO
actions has an imperative, sequential flavor. There is a kind of syntactic sugar called "do-notation" which helps to write sequential operation like these in a more natural way:
do line <- getLine
putStrLn line
Notice that the <-
here is not an operator, but part of the syntactic sugar provided by the do notation.