我从《为美好学习哈斯克尔》第9章中了解到
按照惯例,我们通常不会为
main
指定类型声明。
据我所知,这个公约是广泛的。但是,如果我使用-Wall
标志编译一个缺少main
类型签名的程序,例如
-- test.hs
-- main :: IO ()
main = print (1 :: Int)
GHC确实发出警告:
$ ghc -Wall test.hs
[1 of 1] Compiling Main ( test.hs, test.o )
test.hs:2:1: Warning:
Top-level binding with no type signature: main :: IO ()
Linking test ...
$
我很困惑。。。如果main
的类型签名确实是多余的,为什么-Wall
会在丢失时导致GHC抱怨?指定main
的类型有充分的理由吗?
一般来说,正如该警告所表明的,为顶级绑定提供类型签名总是的好主意。事实上,更合理的说法是
按照惯例,我们确实为everything1指定了一个类型声明。
当然,在一个大项目中,main
本身的工作量是可以忽略的,所以省略签名真的没有任何意义。为了一致性,就把它写出来吧。
然而,尽管Haskell非常适合结构正确的项目,而且实际上有一种在库中编写几乎所有内容的趋势,但它作为一种快速脚本语言也非常好,适用于其他人用Python或Perl编写的东西。在这种情况下,你通常不太关心安全和良好的文档等,你只想快速写下尽可能简洁的内容来完成任务。您通常也不使用-Wall
编译这些脚本,而只使用runhaskell
执行它们。由于脚本总是需要包含main
(与大多数其他Haskell源文件不同),因此在这里省略签名确实足够明智。
我仍然怀疑,现在的大多数Haskeller即使是在最简单的脚本中也会编写main::IO()
,即使只是出于习惯。
1 只有顶层的所有东西,也就是说。本地签名有时也有意义,但通常它们会扰乱代码
实际上,为main
编写类型签名是一个非常好的主意,因为否则,如果你太想用无点形式编写东西,你可能会得到IO (IO ())
类型的main
。这是可以接受的(语言标准说main
只需要具有某种形式的IO a
),但作为main
结果的"内部IO操作"将被丢弃,这几乎肯定不是您想要的(您可能想要join
)。