Haskell's IO does not work like IO in the languages ββyou're used to. All functions in Haskell must be clean: that is, if the function f is called with the argument x , there should be no difference between its call one, two or a hundred times. However, consider what this means for IO. Naive, getLine should be of type getLine :: String or, possibly, getLine :: () -> String . ( () is a single type whose only value is () , it is similar to the void type in C-type language, but there is its only value.) But this will mean that every time you wrote getLine , it should have would return the same string, which is not what you want. This is an IO type goal: encapsulate actions. These actions differ from functions; they are impure calculations (although they themselves are clean). A value of type IO a is an action that, when executed, returns a value of type a . Thus, getLine is of type getLine :: IO String : every time an action is evaluated, a String is created (by reading from the user). Similarly, putStr is of type putStr :: String -> IO () ; this is a function that takes a string and returns an action that when launched does not return any useful information ... but, as a side effect, displays something on the screen.
You are trying to write a function like IO () -> ([Char], Int) . This would be a function that takes action as input and returns a tuple that is not what you want. You want to perform an IO (String, Int) -an action, which when launched creates a tuple consisting of a string (which is a synonym for [Char] ) and an integer. You are also close to your current code! This is what you need:
investinput :: IO (String, Int) investinput = do putStrLn "Enter Username : " username <- getLine putStrLn "Enter Invest Amount : " tempamount <- getLine let amount = read tempamount return (username, amount)
Please note that I made only two changes (and deleted the empty line). Firstly, I changed the type of function, as I said above. Secondly, I changed show to read . The show function is of type Show a => a -> String : this is a function that takes everything that can be shown and creates a string representing it. You wanted read , which is of type Read a => String -> a : given by a string, it parses it and returns some read value.
The other thing you asked about returns a tuple (String, Int) instead of the IO (String, Int) action. There is no pure way to do this; in other words, there is no pure function IO a -> a . Why is this? Because IO a is an unclean action that depends on the real world. If we had such a function impossibleRunIO :: IO a -> a , then we would like it to be so that impossibleRunIO getLine == impossibleRunIO getLine , since the function must be clean. But this is useless, because we would like impossibleRunIO to really interact with the real world! Therefore, this pure function is not possible. Everything that is included in IO never leaves. This is what return does: it is a function, in this case 1 type return :: a -> IO a , which allows you to put pure values ββin IO . For any x , return x is the action that always produces x at startup. This is why you should end your do block with return : username is the pure value you extracted from the action, and as such is only visible in the do block. You need to raise it in IO before the outside world can see it. The same goes for amount / tempamount .
And just for the sake of completeness: behind this there is some kind of comprehensive theory that links it. But this is not at all necessary to start Haskell programming. What I would recommend doing is structuring most of your code as pure functions that add, spindle, and cripple your data. Then build a thin (as thin as possible) IO front layer that interacts with the specified features. You will be surprised how little you need!
1: In fact, it has a more general type, but not relevant at the moment.