“做”在 Haskell 中构建

发布于 2024-10-09 00:18:54 字数 814 浏览 11 评论 0原文

我正在尝试学习 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

我要还你自由 2024-10-16 00:18:54

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

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

通过使 ifend <- hIsEof handle 进一步缩进,它实际上是行延续,而不是 do 中的后续操作代码>.同样,putStrLn line 的缩进量比 line <- hGetLine handle 少,这一事实意味着 do (在 else 内))到此结束。

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.

春夜浅 2024-10-16 00:18:54

有几个问题。首先,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。如果您想更详细地解释您的版本为何/如何不正确,或者错误的含义,请告诉我,我将进行编辑。

There are seveal issues. First, the if is indented too far - end <- ... is assumed to be the last line of the do. 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.

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 }

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.

春夜浅 2024-10-16 00:18:54

你这样写:

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

You wrote this:

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

But it is probably nicer like this:

main :: IO()
main = do
    args <- getArgs
    withFile (head args) ReadMode printFile
牵你的手,一向走下去 2024-10-16 00:18:54

您始终可以使用显式括号 { ; } 永远不必担心这种空白的愚蠢行为。

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

本来就完全没问题(如,不会导致错误)。

在 Haskell 中,I/O 通过特殊的“do”语言进行处理。应该拥抱它。它实际上是通过 monad 实现的,这是一个实现细节。

澄清一下:我不认为大括号更好,我认为它们应该与良好且一致的缩进一起使用。大括号为我们提供了关于代码结构的良好且直接的视觉线索。大多数时候,狂野的缩进当然会造成毫无意义的干扰。而且,大括号为我们的工作代码提供了保证,让我们摆脱了空格意外的无谓担忧。他们消除了这种脆性。

You can always use explicit bracketing with { ; } to never have to worry about this whitespace foolishness.

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文