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 ()
= do
main let line = getLine
putStrLn line
because 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 line
because 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 ()
= do
main <- getLine
line putStrLn line
You need both the do
and the <-
.
The rule is:
If you want to give the
A
a name, use alet
. If theA
is 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