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