'做'在Haskell构建

时间:2010-12-22 20:26:06

标签: haskell syntax io monads do-notation

我正在尝试学习Haskell,并希望编写一个小程序,将文件内容打印到屏幕上。当我将其加载到GHCi时,我收到以下错误:

  

'do'结构中的最后一个语句必须是表达式

我知道这个问题已在此处提出:Haskell — “The last statement in a 'do' construct must be an expression”

即使我的代码非常相似,我仍然无法弄清楚问题。如果有人能够向我指出问题,我会非常感激。

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

4 个答案:

答案 0 :(得分:5)

你的缩进被打破了。这些更好:

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

if进一步缩进而不是end <- hIsEof handle,它实际上是一个续行,而不是do中的后续行动。同样,您putStrLn line缩进比line <- hGetLine handle缩进的事实意味着do(在else内)结束了。

答案 1 :(得分:4)

有一些问题。首先,if缩进太远 - end <- ...被假定为do的最后一行。取消缩进...

下一期出现了。相同的错误消息,仅在第18行。这一次,第19行和第20行没有足够的缩进(它们不会被解析为do的一部分)。缩进(无论如何都看起来更好,因为它现在排成一行)...下一条错误消息。好消息是,这次不是缩进错误,修复也是微不足道的。

test.hs:9:22:
    Couldn't match expected type `([a] -> a) -> [String] -> FilePath'
           against inferred type `IOMode'
    In the second argument of `($)', namely `ReadMode head args'
    In a stmt of a 'do' expression:
        inh <- openFile $ ReadMode head args
    In the expression:
        do { args <- getArgs;
             inh <- openFile $ ReadMode head args;
             printFile inh;
             hClose inh }

修正为inh <- openFile (head args) ReadMode。如果您想要更详细地解释您的版本错误的原因或方式,或错误的含义,请告诉我,我将进行编辑。

答案 2 :(得分:1)

你写了这个:

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

但它可能更好:

main :: IO()
main = do
    args <- getArgs
    withFile (head args) ReadMode printFile

答案 3 :(得分:1)

您始终可以使用{ ; }明确包围,从而不必担心这种空白的愚蠢行为。

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

会完全没问题(因为,不会导致错误)。

I / O通过Haskell中的特殊“do”语言处理。它应该被接受。它实际上是通过monad实现的,是一个实现细节。

澄清一下:我认为牙箍不是更好,我认为它们应该与一个漂亮而一致的缩进相结合。大括号为代码的结构提供了很好的直观视觉线索。在大多数情况下,野蛮缩进当然会是一种毫无意义的分心。而且,括号为我们提供了工作代码的保证,并使我们免受空白事故的无意义担忧。他们消除了这种脆弱。