How to get the String out of the IO String in Haskell

Date 2024-10-02

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 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 ()
main = do     
  line <- getLine   
  putStrLn line

You need both the do and the <-.

The rule is:

If you want to give the A a name, use a let. If the A is inside an IO, use <- inside a do.

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

Start your Haskell project from a template

Haskell templates
Next
Announcing autodocodec-nix and Nix integration for opt-env-conf