Why can't I use the expression (cnt <- hGetContents h) instead of cnt?
I am studying Haskell. It works great:
import System.IO main = do h <- openFile "text.txt" ReadMode cnt <- hGetContents h mapM_ putStrLn $ lines cnt hClose h
But this doesn't work:
import System.IO main = do h <- openFile "text.txt" ReadMode mapM_ putStrLn $ lines (cnt <- hGetContents h) hClose h
Why isn't my second option working? I expected both options to be equal because it (cnt <- hGetContents h)
is an expression and also returns a value.
source share
The problem is, what cnt <- hGetContents h
is an expression is not , it's special syntactic sugar inside to do the notation . This means that this is another way of writing the following normal Haskell code:
hGetContents h >>= \ cnt -> {- rest of do block -}
The part before {- rest of the do block -}
here is not an integer expression, as the rest of the do block is needed to complete the lambda body.
You can manually remove it to get something like:
hGetContents h >>= \ cnt -> mapM_ putStrLn (lines cnt)
or the dissolute version
hGetContents h >>= mapM_ putStrLn . lines
You can tell this is a special expression because it introduces a new identifier ( cnt
) that you can use throughout the rest of your code, outside of the expression itself. This is not what normal Haskell expressions allow you to do (at least not without compile-time magic).
source share
cnt <- hGetContents h
is essentially syntactic sugar for hGetContents h >>= \cnt ->
.
It's not an expression, it's sugar meant for its own line in the do block.
If you still want to keep it on one line, you can do so, although later on you won't be able to reference the contents of the file:
import System.IO main = do h <- openFile "text.txt" ReadMode hGetContents h >>= mapM_ putStrLn . lines hClose h
source share