“做”在 Haskell 中构建
我正在尝试学习 Haskell,并想编写一个小程序,将文件的内容打印到屏幕上。当我将其加载到 GHCi 中时,出现以下错误:
“do”结构中的最后一个语句必须是表达式
我知道这个问题已经在这里被问过:Haskell —“'do' 构造中的最后一个语句必须是表达式”。
尽管我的代码非常相似,但我仍然无法找出问题所在。如果有人能向我指出问题,我将非常感激。
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
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
你的缩进被破坏了。这些更好:
通过使
if
比end <- hIsEof handle
进一步缩进,它实际上是行延续,而不是do
中的后续操作代码>.同样,putStrLn line
的缩进量比line <- hGetLine handle
少,这一事实意味着do
(在else 内)
)到此结束。Your indentation is broken. These are better:
By having
if
further indented thanend <- hIsEof handle
, it was actually a line continuation, not a subsequent action in thedo
. Similarly, the fact that you hadputStrLn line
less indented thanline <- hGetLine handle
means that thedo
(inside theelse
) ended there.有几个问题。首先,
if
缩进得太远 -end <- ...
被假定为do
的最后一行。未缩进...下一个问题出现。同样的错误消息,仅在第 18 行。这一次,第 19 行和第 20 行缩进得不够深(它们没有被解析为
do
的一部分)。缩进(无论如何看起来更好,因为现在一切都排列好了)...下一个错误消息。好消息是,这次不是缩进错误,而且修复也很简单。修复方法是
inh <- openFile (head args) ReadMode
。如果您想更详细地解释您的版本为何/如何不正确,或者错误的含义,请告诉我,我将进行编辑。There are seveal issues. First, the
if
is indented too far -end <- ...
is assumed to be the last line of thedo
. Unindent...next issue comes up. Same error message, only at line 18. This time, line 19 and 20 are not indented deeply enough (they aren't parsed as part of the
do
). Indent (looks nicer anyway, since it all lines up now)... next error message. The good news is, it's not an indentation error this time and the fix is again trivial.The fix is
inh <- openFile (head args) ReadMode
. If you want a more detailed explanation of why/how your version is incorrect, or what the error means, let me know and I'll edit.你这样写:
但这样可能更好:
You wrote this:
But it is probably nicer like this:
您始终可以使用显式括号
{ ; }
永远不必担心这种空白的愚蠢行为。本来就完全没问题(如,不会导致错误)。
在 Haskell 中,I/O 通过特殊的“
do
”语言进行处理。应该拥抱它。它实际上是通过 monad 实现的,这是一个实现细节。澄清一下:我不认为大括号更好,我认为它们应该与良好且一致的缩进一起使用。大括号为我们提供了关于代码结构的良好且直接的视觉线索。大多数时候,狂野的缩进当然会造成毫无意义的干扰。而且,大括号为我们的工作代码提供了保证,让我们摆脱了空格意外的无谓担忧。他们消除了这种脆性。
You can always use explicit bracketing with
{ ; }
to never have to worry about this whitespace foolishness.would have been totally fine (as in, not cause the error).
I/O is dealt with through the special "
do
" language, in Haskell. It should be embraced. That it is actually implemented via monads is an implementational detail.To clarify: I don't think braces are better, I think they should go together with a nice and consistent indentation. Braces give us nice and immediate visual clues as to the code's structure. Wild indentation will of course be a pointless distraction most of the time. But also, braces give us a guarantee for the working code, and relieve us from the pointless worries of whitespace accidents. They remove this brittleness.