0

I am fiddling around with IO and i do not understand the following error :

* Ambiguous type variable `a0' arising from a use of `readLine'
      prevents the constraint `(Console a0)' from being solved.
      Probable fix: use a type annotation to specify what `a0' should be.
      These potential instance exist:
        instance Console Int -- Defined at Tclass.hs:8:14
    * In the second argument of `(+)', namely `readLine'
      In the second argument of `($)', namely `(2 + readLine)'
      In the expression: putStrLn . show $ (2 + readLine)
   |
17 |     useInt =putStrLn . show $ (2+readLine)

Code

module Tclass where
    import System.Environment

    class Console a where
        writeLine::a->IO()
        readLine::IO a

    instance Console Int where
        writeLine= putStrLn . show 

        readLine = do
            a <- getLine
            let b= (read  a)::Int
            return b

    useInt::IO()
    useInt =putStrLn . show $ (2+readLine)  

P.S i do not understand shouldn't the compiler infer the type of the instance for readLine and make the addition with 2 in the useInt method ?

Bercovici Adrian
  • 8,794
  • 17
  • 73
  • 152

1 Answers1

3

2 is not only an Int in Haskell but it is of any numeric type, including Float,Double,Integer,.... Its type is Num a => a -- a polymorphic type fitting each numeric type.

So, you could use (2::Int) instead. Then you'll discover that (2::Int) + readLine is a type error, since readLine :: Int is wrong, we only get readLine :: IO Int.

You can try this, instead

useInt :: IO ()
useInt = do
   i <- readLine
   putStrLn . show (2 + i :: Int)
chi
  • 111,837
  • 3
  • 133
  • 218
  • I do not understand the following: Shouldn't the `readLine` method return an `Int` when used by another method since the only `IO` part was finished with `a<-getLine` ,so after this line shouldn't the returning result be a pure one?So if i have a method `mymethod::IO Char` that is used by another method `secondMethod` i still need to access the `mymethod` result with `<-` inside the `secondMethod`? – Bercovici Adrian Jun 26 '18 at 12:07
  • So a correct compact way it should be: `useInt::IO() useInt =putStrLn . show $ ((2::Int)+(<-readLine))` ? Can you oneline the (<-) operator? – Bercovici Adrian Jun 26 '18 at 12:13
  • 1
    @BercoviciAdrian `<-` is not an operator itself but syntactic sugar. What you need here is the _monadic chaining combinator_ [`=<<`](http://hackage.haskell.org/package/base-4.11.1.0/docs/Control-Monad.html#v:-61--60--60-). `useInt = print . ((2::Int)+) =<< readLine`. (That's indeed also what `do {i<-readLine; print (2+i::Int)}` desugars to.) – leftaroundabout Jun 26 '18 at 13:00
  • 2
    @BercoviciAdrian `readLine` is an `IO Int`, not an `Int`. The former type says "you could have an int, if you let me do I/O", the latter says "you can have an int (without I/O)". The `.. <- ..` syntax in `do` blocks lets you run the IO action and get its result (which is now I/O-free). However, the whole `do` expression will have an IO type (since it did I/O after all!). Note that `do x <- readLine ; f x` runs `getLine` once, while `g readLine` passes the whole IO action `readLine` to `g` which might use it twice e.g. `g act = do x<-act; y<-act; ...` – chi Jun 26 '18 at 13:27
  • 1
    @BercoviciAdrian Maybe you should read a monad tutorial to know more about the IO monad, and/or have a look at [this answer of mine](https://stackoverflow.com/a/28625714/3234959) which could clarify some aspects. – chi Jun 26 '18 at 13:28
  • But this means that if i have a hierarchy of 3 methods `m0` ,`m1`,`m2` where `m0::IO a` and `m1` uses `m0` , and `m2` uses `m1` , then i have to always get the value "out of the monad bind" am i right? `m2=< – Bercovici Adrian Jun 26 '18 at 13:42