Answer: With <-
You get the String out of the IO String with <-.
Example in GHCI
You have getLine :: IO String and you want to get the String.
You can't "just" let line = getLine :: String because then you'll see:
<interactive>:3:12: error: [GHC-83865]
• Couldn't match type: IO String
with: [Char]
Expected: String
Actual: IO String
• In the expression: getLine :: String
In an equation for ‘line’: line = getLine :: String
You have to line <- getLine :: IO String. In GHCI that looks like this:
ghci> line <- getLine :: IO String hello ghci> :t line line :: String
As you can see we "got the String out of the IO String" with <-.
Example with main
This does not work:
main :: IO ()
main = do
let line = getLine
putStrLn linebecause then you see
file.hs:4:12: error: [GHC-83865]
• Couldn't match type: IO String
with: [Char]
Expected: String
Actual: IO String
• In the first argument of ‘putStrLn’, namely ‘line’
In a stmt of a 'do' block: putStrLn line
In the expression:
do let line = getLine
putStrLn line
|
4 | putStrLn line
|
You also can't "just" use let like this:
main :: IO ()
main =
let line = getLine
in putStrLn linebecause then you see the same error:
file.hs:4:15: error: [GHC-83865]
• Couldn't match type: IO String
with: [Char]
Expected: String
Actual: IO String
• In the first argument of ‘putStrLn’, namely ‘line’
In the expression: putStrLn line
In the expression: let line = getLine in putStrLn line
|
4 | in putStrLn line
| ^^^^
Instead you have to use <- inside a do, like this:
main :: IO ()
main = do
line <- getLine
putStrLn lineYou need both the do and the <-.
The rule is:
If you want to give the
Aa name, use alet. If theAis inside anIO, use<-inside ado.
But how does this really work?
To understand this completely, you need to understand (easiest in this order):
Data types
Data constructors
Type constructors
Type classes
Higher-kinded types
The type of
>>=Desugaring
Go learn about those first if you really want to understand. Chances are that you will already understand by the time you're done.
In short; This code:
main :: IO ()
main = do
line <- getLine
putStrLn line
gets desugared to this code:
main :: IO ()
main =
getLine >>= \line ->
putStrLn line