Read single line from stdin in Haskell using IO.readLn

26,481

Solution 1

readLn as the type: Read a => IO a. It reads a line from the user, and then parses the string into type a. What is type a? It is whatever you want (as long as it is an instance of Read). For example:

readAInt :: IO Int
readAInt = readLn

readABool :: IO Bool
readABool = readLn

print has the type Show a => a -> IO (). It takes a type that is an instance of Show, and prints it out. For example, to print True, you can use print True. To print the Int 42, you can use print 42.


In your example, you are using print and readLn together. This doesn't work, as haskell can't figure out what type readLn should return. print can take any type that is showable, so it doesn't restrict to one what type would be returned. This makes the return type of readLn ambiguous as haskell can't figure out the type. This is what the error message is saying.


What you probably what it to store just the string being entered by the user, rather than reading it into your own type. You can do this with getLine, which has the type getLine :: IO String. Similarily you can use putStrLn instead of print to just print a String. putStrLn has the type String -> IO ().

Solution 2

This is what you changed your code to, right?

import System.IO

main = do
    z <- readLn
    putStrLn z

putStrLn writes a String to stdout, so z is a String. Therefore readLn will read a String from stdin.

BUT... readLn expects to read a Haskell-formatted value from stdin. i.e. instead of expecting you to type something like This is a string, it anticipates it in quote marks: "This is a string".

To fix, replace readLn with getLine, which reads in literal text, not a Haskell-formatted string.

import System.IO

main = do
    z <- getLine
    putStrLn z

Solution 3

readLn reads back a type that you specify, and so can't be used in this way: it needs to be used in a function that specifies its type. getLine, on the other hand, always returns a String, so it does what you want.

It's worth noting that you might want to use putStrLn instead of print as well; print will add quotation marks.

Thus do { z <- getLine; putStrLn z; } in GHCi should do what you want.

Share:
26,481
Betamos
Author by

Betamos

Web developer and full time computer science student in Stockholm, Sweden. Interested in various programming languages like PHP, java, JavaScript. Currently I'm excited by game development in JavaScript and Drupal. I'm also very familiar with the 3D-tools Cinema 4D and Maxwell Render.

Updated on December 22, 2021

Comments

  • Betamos
    Betamos over 2 years

    This code does not compile in GHC 7.0.3:

    import System.IO
    
    main = do
        z <- readLn
        print z
    

    My intention is to read one line from stdin and store it in z, to do more advanced stuff with it later on. Error message looks like:

    test.hs:5:9:
        Ambiguous type variable `a0' in the constraints:
          (Show a0) arising from a use of `print' at test.hs:5:9-13
          (Read a0) arising from a use of `readLn' at test.hs:4:14-19
        Probable fix: add a type signature that fixes these type variable(s)
        In a stmt of a 'do' expression: print z
        In the expression:
          do { z <- readLn;
               print z;
               return () }
        In an equation for `main':
            main
              = do { z <- readLn;
                     print z;
                     return () }
    

    Obviously there is something fundamental I haven't understood yet; please explain to me why it doesn't work and how to fix it.

    EDIT1: I fixed the compile error by changing print z to putStrLn z, so GHC understands that I want to read a string. But when I run the program, I get a runtime error which I can't understand:

    $ ./test
    hello!
    test: user error (Prelude.readIO: no parse)
    $
    

    I just typed "hello!" and then enter. Note that I'm running x86_64 GHC on OS X, which is considered unstable.

    EDIT2: I changed readLn to getLine and it magically works for no reason. I would like to know why, but I'm happy it works.

    Final code:

    import System.IO
    
    main = do
        z <- getLine
        print z