I am still struggling with Haskell and now I have encountered a problem with wrapping my mind around the Input/Output monad from this example:
main = do line <- getLine if null line then return () else do putStrLn $ reverseWords line main reverseWords :: String -> String reverseWords = unwords . map reverse . words I understand that because functional language like Haskell cannot be based on side effects of functions, some solution had to be invented. In this case it seems that everything has to be wrapped in a do block. I get simple examples, but in this case I really need someone's explanation:
- Why isn't it enough to use one, single
doblock for I/O actions? - Why do you have to open completely new one in if/else case?
- Also, when does the -- I don't know how to call it -- "scope" of the
domonad ends, i.e. when can you just use standard Haskell terms/functions?
dois just syntactic sugar to avoid having to write overly complex statements with>>=and>>it works with all monads, and has no special association with IO. You don't have to use a seconddoin the example code(you don't even need the firstdobut the resulting code would be harder to read), you could also writeelse putStrLn (reverseWords line) >> mainand it would have the same effect.