为什么Main.main
的类型必须是IO ()
而不是IO String
或IO Int
或IO whatever
?
main :: IO ([] Char) -- Type error
main = (>>) ((>>=) getLine putStrLn) getLine
答案 0 :(得分:5)
如果您将IO a
视为" IO
计算产生a
"然后它引出了一个问题,即运行时对a
生成的main
的影响。它可以放弃它。这需要像
void :: IO a -> IO () -- defined more generally in Control.Monad
然后给我们
realMain :: IO ()
realMain = void main
除了文档之外,这没有特别的问题。如果我问你IO a
的价值,那么我可能会选择用a
做些什么。如果我要求IO ()
的价值,那么这种不确定性就会减少:我可以随时创造()
我自己的价值,我不需要你,因此我只关心这一方面运行IO
计算的效果。
这更好地匹配main
的实际用法,因此为了更好的类型清晰度,Haskell运行时可能会要求main :: IO ()
。
这也迫使main
的创建者明确表达他们对任何"返回值"他们创造。如果我有一个mainish :: IO a
,那么在将其交给运行时之前我需要明确地void
。
所有人都说,正如Sibi指出的那样,GHC实际接受main :: IO a
并默默地丢弃a
,所以这一点有点没有实际意义。请参阅Haskell报告的Chapter 5简介。
答案 1 :(得分:4)
main
的类型可以是IO a
。这个样子:
main :: IO Int
main = do
putStrLn "test"
return 2
然后你可以自己执行:
$ ghc -o test test.hs
[1 of 1] Compiling Main ( test.hs, test.o )
Linking test ...
$ ./test
test
main
是程序开始执行的功能。因此,类型为main
的{{1}}函数没有多大意义,因为其他函数实际上不会使用IO a
中包含的a
。
答案 2 :(得分:1)
实际上,main
可以是某个类型IO T
T
不是()
。
我认为这不是一个错误,但这不是一个错误。 main
没有理由成为其他IO ()
类型的任何类型,它可能会导致非常微妙的运行时问题,例如
main = putStrLn <$> getContents
我遇到了一个问题需要一段时间来弄明白。当然,这可以通过始终为所有顶级定义(每个人都应该这样做)提供类型签名来防止,但我仍然觉得没有理由允许除main
之外的任何IO类型。 IO ()
。
(上述代码的问题是main
实际上评估的是包含 IO操作的IO操作,而不是实际上是IO操作。即,类型为{{ 1}}。正确的代码可以是main :: IO (IO ())
或main = join $ putStrLn <$> getContents
)。