Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read from stdin in Haskell using IO.readLn

Tags:

io

haskell

ghc

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
like image 752
Betamos Avatar asked Oct 18 '11 01:10

Betamos


People also ask

How do I print a statement in Haskell?

If you have a String that you want to print to the screen, you should use putStrLn . If you have something other than a String that you want to print, you should use print . Look at the types! putStrLn :: String -> IO () and print :: Show a => a -> IO () .

How does Haskell IO work?

Haskell separates pure functions from computations where side effects must be considered by encoding those side effects as values of a particular type. Specifically, a value of type (IO a) is an action, which if executed would produce a value of type a .


3 Answers

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 ().

like image 115
David Miani Avatar answered Oct 01 '22 06:10

David Miani


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
like image 28
dave4420 Avatar answered Oct 01 '22 04:10

dave4420


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.

like image 10
cge Avatar answered Oct 01 '22 04:10

cge