主返回IO Something而不是IO()的用途是什么?

gaa*_*kam 4 io haskell program-entry-point

我正在阅读http://learnyouahaskell.com/ ...令我惊讶的是:

因此,main始终具有类型签名main :: IO something,其中something是一些具体类型。

?因此main,不必一定是type IO(),而可以是IO(String)or 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:~$
Run Code Online (Sandbox Code Playgroud)

嗯 因此,我的第一个假设被反驳。我认为这是Haskell程序将退出状态返回到Shell的一种方式,就像C程序从其启动int main()并使用return 0或报告退出状态一样return 1

但是1没有,上面的程序消耗了from输入的内容,然后什么也不做,特别是似乎没有将其返回1给shell。

再测试一次:

m@m-X555LJ:~$ cat wtf.hs
main = getContents
m@m-X555LJ:~$ runhaskell wtf.hs
m@m-X555LJ:~$ 
Run Code Online (Sandbox Code Playgroud)

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

这表明该值实际上没有返回任何地方:显然,由于没有在任何getContents地方使用的结果,由于懒惰,整个指令被跳过了。但是,如果是这种情况,为什么IO Int不跳过返回?是的:我做fmap read了这个IO动作;但是同样的东西似乎也适用,read仅在使用操作结果的情况下才需要计算,而该结果(如main = getContents示例所示)没有使用,因此懒惰也应该跳过read,因此也跳过getLine,对吗?好吧,错了-但是我很困惑为什么。

有什么用返回的IO Something距离main,而不是唯一的IO ()

Cub*_*bic 6

这实际上是多个问题,但顺序如下:

  1. 的“结果” main没有意义,这就是为什么它可以()或其他任何含义的原因。根本不使用。
  2. 除了IO ()main 之外的其他原因类型是为了方便起见;否则,您总是必须要做一些main = void $ realMain丢弃结果的操作(您可能希望执行一个操作,该操作可能会返回您不关心的结果,作为最后发生的事情),这有点乏味。恕我直言,默默地丢弃东西是不好的,所以我宁愿如果main被迫这样做:: IO (),但您始终可以通过自己提供类型签名来获得这种效果,因此实际上这不是问题。
  3. 重点:如果您要退出并使用特定的退出代码,请使用 System.Exit
  4. 之所以fmap read getLine会消耗输出而getContents不会消耗输出,是因为它getContents是懒惰的,getLine而不是-即getLine会在您认为合适的地方读取一行文本,而getContents只有在Haskell世界中“需要”结果的情况下,才执行任何实际的IO。由于的结果IO不会用于任何事情,这意味着如果getContents整个结果都不会做任何事情main