Search code examples
haskellsyntaxiomonadsdo-notation

'do' construct in Haskell


I'm trying to learn Haskell and want to write a small program which prints the content of a file to the screen. When I load it into GHCi I get the following error:

The last statement in a 'do' construct must be an expression

I know this question has be asked already here: Haskell — “The last statement in a 'do' construct must be an expression”.

Even though my code is very similar I still can't figure out the problem. If anyone could point out the problem to me I'd be very thankful.

module Main (main) where

import System.IO
import System(getArgs)

main :: IO()
main = do
    args <- getArgs
    inh <- openFile $ ReadMode head args
    printFile inh
    hClose inh

printFile :: Handle -> IO ()
printFile handle = do
    end <- hIsEOF handle
        if end
            then return ()
            else do line <- hGetLine handle
                putStrLn line
                printFile handle

Solution

  • Your indentation is broken. These are better:

    printFile :: Handle -> IO ()
    printFile handle = do
        end <- hIsEOF handle
        if end
            then return ()
            else do line <- hGetLine handle
                    putStrLn line
                    printFile handle
    
    printFile :: Handle -> IO ()
    printFile handle = do
        end <- hIsEOF handle
        if end
            then return ()
            else do
                line <- hGetLine handle
                putStrLn line
                printFile handle
    

    By having if further indented than end <- hIsEof handle, it was actually a line continuation, not a subsequent action in the do. Similarly, the fact that you had putStrLn line less indented than line <- hGetLine handle means that the do (inside the else) ended there.