Haskell 是否应该为main指定类型签名?为什么?
我从中吸取了教训 按照惯例,我们通常不为Haskell 是否应该为main指定类型签名?为什么?,haskell,main,conventions,compiler-flags,type-signature,Haskell,Main,Conventions,Compiler Flags,Type Signature,我从中吸取了教训 按照惯例,我们通常不为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 bin
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
的类型是否有充分的理由(除了去掉该警告之外)?一般来说,正如该警告所表明的,给顶级绑定一个类型签名总是一个好主意。事实上,这样说更为合理
按照惯例,我们确实为所有内容1指定了一个类型声明
当然,在一个大项目中,main
本身是一项不可忽视的工作,因此省略签名确实没有任何意义。为了前后一致,把它写下来
然而,尽管Haskell非常适合于结构合理的项目,而且实际上有在库中编写几乎所有内容的趋势,但它作为一种快速脚本语言也出人意料地好,因为其他人会用Python或Perl编写。在这些情况下,您通常不太关心安全性和良好的文档等,您只想快速地写下尽可能简洁的内容来完成这项工作。您通常也不会使用-Wall
编译这些脚本,而只是使用runhaskell
执行它们。由于脚本总是需要包含main
(与大多数其他Haskell源文件不同),因此在这里省略签名确实是明智的
我仍然怀疑,现在大多数Haskeller确实是用最简单的脚本编写main::IO()
,如果只是出于习惯的话
1也就是说,只有顶层的所有内容。本地签名有时也有意义,但通常它们会使代码变得混乱。实际上为
main
编写类型签名是一个非常好的主意,因为否则,如果您太喜欢尝试以无点形式编写内容,您最终可能会得到main
类型的IO(IO())
。这是可以接受的(语言标准说,main
只需要有某种形式的ioa
),但是由main
产生的“内部IO动作”将被丢弃,这几乎肯定不是你想要的(你可能想加入它).感谢您的澄清。对于更大的项目,启用-fwarn缺失签名和-Werror
,这将强制main
具有类型签名也是有意义的。@PetrPudlák我通常使用-Wall
(我相信这将启用-fwarn缺失签名)与-Werror
一起使用。缺少顶级类型签名应为错误。事实上,它应该是非法的。非法的应该作为犯罪受到惩罚。在该语言中不是非法的。特别是,顶级导出类型签名可能是错误的。我使用了很多非常通用的助手,它们没有导出,没有公共文档,并且签名比身体长。把这些写出来没有任何帮助,只是一件烦人的事。这本书只是说,它们不会为main
提供类型注释,以减少演示文稿中的混乱。他们并不是在暗示你不应该对它进行注释。@chi有趣;我不是那样读的。不过,我不确定这句话应该怎么解释。另一个模棱两可的“我们”的例子。很有趣。您是否可以添加一个链接,指向在标准中您阅读到的main
只需要某种形式的ioa
?@Jubobs:请参阅第二段,我认为不需要main::IO()
是标准的一个(非常)小的缺陷。然而,这是个人喜好的问题。当main
以IO(IO a)
结尾时,您是否可以添加这样一个示例?@PetrPudlák是一个精心设计的示例:main=return getLine
,类型为IO(IO String)
。