Haskell IO Example

I read about the deeper actions of the IO monad in Haskell on their wiki , and I came across this code

main = do a <- ask "What is your name?" b <- ask "How old are you?" return () ask s = do putStr s readLn 

That makes sense to me. The ask function should print the string passed to it and return a string that can be passed to a or b.

However, uploading this to GHCi, I get problems. Reports that there is no Read instance from using ask and that I can import GHC.Read. It's not obligatory. This code was on Haskell.org, so I think it should work. Has anything been changed in the language or is there some kind of big understanding that I am missing?

+4
source share
2 answers

I made two code changes.

  • Correct indentation - remember that haskell is "space sensitive", so please make sure that the code looks correctly aligned
  • Explicit type signatures. This is a bit complicated. But as a rule of thumb, when the code you would expect to work does not work. Try annotating your code with types as shown below. You will understand why this is so on time.

Here's the modified code:

 main = do a <- askString "What is your name?" b <- askOther "How old are you?" putStrLn "" putStrLn "Name and age" putStrLn (a :: String) print (b :: Int) return () askString s = do putStrLn s getLine askOther s = do putStrLn s readLn 

Edit: Sorry, the code is really compiling. Again, as your haskell matures, you will see why askString and askOther look different. Here is an example of execution:

 $ runghc Hello.hs What is your name? Arash How old are you? 22 Name and age Arash 22 
+4
source

If you create a file with only the ask function (without the main problem) and upload it to ghci, you can see what the request type is

 ask :: (Read a) => String -> IO a 

means that it is polymorphic in the return type.

The problem is that when you do

 a <- ask "What is your name" 

the compiler needs to know what type a , so it can use the correct deserialization function for the line you are reading from inpout. But a not used anywhere and there are no type signatures, since type inference cannot infer type a . The compiler refuses and gives you a message like "ambiguos types".

There are two main ways to fix this:

  • Make the ask function always return the same type. You can do this by adding a specific signature

     ask :: String -> IO String 

    Or by changing readLn to something like getLine .

  • Add type signatures in which you use polymorphic functions. You can either add a type signature to the request request itself:

     a <- ask "What is your name" :: IO String 

    or you can add it directly to the variable

     (a :: String) <- ask "What is your name" 

    however, this second parameter is not enabled by default in Haskell syntax. you need to enable the ScopedTypeVariables extension by adding the following comment as the first line in your file

     {-# LANGUAGE ScopedTypeVariables #-} 
+7
source

All Articles