main 返回 IO Something 而不是 IO() 有什么用?

What's the use of main returning IO Something rather than IO()?

我正在阅读 http://learnyouahaskell.com/ ... 让我感到惊讶的是:

Because of that, main always has a type signature of main :: IO something, where something is some concrete type.

?所以 main 不一定是 IO() 类型,而是可以是 IO(String)IO(Int)?但这有什么用呢?

我玩了一些...

m@m-X555LJ:~$ cat wtf.hs
main :: IO Int
main = fmap (read :: String -> Int) getLine
m@m-X555LJ:~$ runhaskell wtf.hs
1
m@m-X555LJ:~$ echo $?
0
m@m-X555LJ:~$

嗯。所以我的第一个假设被推翻了。我认为这是 Haskell 程序从 return 退出状态到 shell 的一种方式,就像 C 程序从 int main() 开始并使用 [= 报告退出状态一样20=] 或 return 1.

但是没有:上面的程序从输入中消耗了 1 然后什么都不做,特别是似乎没有 return 这个 1 到 shell.

再测试一次:

m@m-X555LJ:~$ cat wtf.hs
main = getContents
m@m-X555LJ:~$ runhaskell wtf.hs
m@m-X555LJ:~$ 

哇。这次我尝试 returning IO String。由于我不知道的原因,这次 Haskell 甚至 甚至 都没有等待输入,就像我 returning IO Int 时那样。该程序似乎什么都不做。

这暗示该值实际上未在任何地方 return 编辑:显然,由于 getContents 的结果未在任何地方使用,因此由于懒惰而跳过了整个指令。但如果是这样的话,为什么 returning IO Int 没有被跳过?是的:我在 IO 动作上做了 fmap read;但同样的东西似乎适用,只有在使用操作结果时才需要计算 read,而正如 main = getContents 示例似乎暗示的那样 - 未使用,因此懒惰也应该跳过read,因此也是 getLine,对吧?好吧,错了 - 但我很困惑为什么。

main 而不是仅 IO () returning IO Something 有什么用?

这其实是多道题,但是顺序是:

  1. main 的 'result' 没有意义,这就是为什么它 可以 () 或其他任何东西。根本没用过。
  2. main 允许 IO () 以外的类型是为了方便;否则你总是不得不做类似 main = void $ realMain 的事情来丢弃结果(你可能希望有一个可以 return 一个你不关心的结果的动作作为最后发生的事情)这有点乏味。恕我直言,默默地丢弃东西是不好的,所以我更喜欢 main 被强制为 :: IO (),但你总是可以通过自己提供类型签名来获得这种效果,所以这在实践中并不是真正的问题.
  3. 旁白:如果您想使用特定的退出代码退出,请使用System.Exit
  4. fmap read getLine 消耗输出而 getContents 不消耗输出的原因是因为 getContents 是懒惰的而 getLine 不是 - 即 getLine 读取一行文本,你认为它确实如此,而 getContents 仅在 Haskell 世界中结果为 "needed" 时才执行任何实际 IO;由于 IO 的结果没有用于任何事情,这意味着如果 getContents 是你的整个 main.
  5. 它什么也不会做