4 回答
你的缩进被打破了。这些更好:
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
)在此处结束。
有几个问题。首先,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
. 如果您想更详细地解释为什么/如何您的版本不正确,或者错误意味着什么,请告诉我,我会进行编辑。
你写了这个:
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
您始终可以使用显式括号,{ ; }
而不必担心这种空白愚蠢。
printFile :: Handle -> IO ()
printFile handle = do {
end <- hIsEOF handle ;
if end
then return ()
else do { line <- hGetLine handle ;
putStrLn line ;
printFile handle }}
本来完全没问题(如,不会导致错误)。
do
在 Haskell 中,I/O 是通过特殊的 " " 语言处理的。它应该被接受。它实际上是通过 monads 实现的,这是一个实现细节。
澄清一下:我不认为大括号更好,我认为它们应该与一个漂亮且一致的缩进一起使用。大括号为我们提供了关于代码结构的良好且直接的视觉线索。大多数时候,狂野的缩进当然是一种毫无意义的干扰。而且,大括号为我们的工作代码提供了保证,并让我们摆脱了空白事故的无意义担心。他们消除了这种脆弱性。