I am a complete beginner to Haskell, although familiar to the functional paradigm in languages like Python, F#, Java, C# and C++(in a limited way).
Something that just keeps escaping me is IO in haskell. I tried several times, even learned C# and F# in between my tries of getting around it.
To be more specific I am referring to getting IO without do notation, using do notation, IO becomes trivial. It might be bad practice, but in my spare time I like to see if I can get things done in one continuous expression. As much of a bad practice as that is, it is fun.
Such an expression is usually of the sort(in pseudo-haskell):
main = getStdinContentsAsString
>>= ParseStringToDataStructureNeeded
>>= DoSomeComputations
>>= ConvertToString
>>= putStrLn
I have no problem with the last four parts. One of the reasons I learned F# was just to see if there was something i was not getting my head around aside from IO, but as soon as I had the convenient Console.ReadLine() of F# which returns a plain old String it was basically smooth sailing.
Which brings me back to another go at haskell, again stopped by the IO mechanism.
I have managed(using another question here) to get reading a int from the console, and print "Hello World!" that many times
main = (readLn :: IO Int) >>= \n -> mapM_ putStrLn $ replicate n "Hello World!"
I would like to get at least some "general use" way to just read the whole contents of the stdin(possibly multiple lines, so getContents would need to be the function of choice) as a string, and then i can process the string using other functions like unlines and then map.
Some of the things that I already tried:
As I said, getContents would be what I need(unless there is some equivalent to it).
Using logic, since
getContents :: IO String
Then I would need something that takes an IO String and returns a lain old String. Which is(as far as i know)
unsafePerformIO :: IO a -> a
However for some reason ghc is not happy:
* Couldn't match type `[Char]' with `IO (IO b)'
Expected type: String -> IO b
Actual type: IO (IO b) -> IO b
* In the second argument of `(>>=)', namely `unsafePerformIO'
In the expression: getContents >>= unsafePerformIO
Another thing I tried: this works without a problem;
main = getContents >>= putStrLn
Even though the type returned by getContents is an IO action and not the per se String that putStrLn wants
getContents :: IO String
putStrLn :: String -> IO ()
Somehow the action is magically executed and the resulting string is passed into the put function.
But then when I try to add something in, like simply appending " hello" to the input before printing it:
main = getContents >>= (++ " hello") >>= putStrLn
I suddenly get a type mismatch:
Couldn't match type `[]' with `IO'
Expected type: String -> IO Char
Actual type: [Char] -> [Char]
* In the second argument of `(>>=)', namely `(++ " hello")'
In the first argument of `(>>=)', namely
`getContents >>= (++ " hello")'
In the expression: getContents >>= (++ " hello") >>= putStrLn
Somehow the IO action isn't executed anymore(or maybe I just don't understand this).
I have also tried numerous things, with combinations of getLine, readLn, getContents, unsafePerformIO, read, fmap to no avail.
This is just a very basic example but it illustrates perfectly the problem that made me give up haskell several times now(and probably I'm not the only one), although the stubbornness of wanting to get my head around it, and learn what is pretty much THE functional programming language keeps me coming back.
To conclude:
Is there something I'm not getting?(99% yes)
If yes, then what?
How should I go about reading the whole stdin and processing it all in one continuous expression?(If I need only 1 line, I guess whatever the solution is, it would also work with getLine sine it is basically the sister of getContents)
Thanks in advance!
IOmonad and simple values. If you dom >>= f, the content wrapped inIOis passed tof.fhas signaturef :: a -> IO b, so it produces another (well possibly the same) value wrapped in anIOmonad. SogetContents >>= (++ " hello")makes no sense, since(++ "hello")does not return anIO b. You can however usegetContents >>= putStrLn . (++ " hello")getContents >>= (++ " hello"), aString(or[Char]) should be what is passed on into(++ " hello"), right? And(++ " hello")has type:: [Char] -> [Char]so if a String is passed into(++ " hello"), what is the problem?interactfunction.main = interact (++ " hello")donotation and then desugar it manually, or think about what the expression you wrote manually using>>=would look like indonotation. For example, your erroneous expressiongetContents >>= (++ " hello") >>= putStrLncorresponds to thedonotationdo { x <- getContents; y <- x ++ " hello"; putStrLn y }, making it clear where the error is: you havey <-, so the right-hand side must be anIOaction, but instead it’s just aString. One solution is to wrap it inpure(orreturn) to make it an action.