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.

+3


source share


2 answers


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).

+7


source


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

      

+2


source







All Articles