为什么Haskell中的main函数没有任何参数?



我对Haskell有点陌生。我学过一两个教程,但经验不多。

Haskell中的每个函数都是纯函数,这就是为什么没有io单子我们就不能有任何I/O。我不明白的是,为什么程序参数也必须是IO动作?参数像传递给函数一样传递给程序。为什么不能像在函数中那样访问参数?

说得更清楚些,我不明白,为什么main函数必须是这样的

main :: IO()
main = do
args <- getArgs
print args

而不是

main :: [String] -> IO()
main args = do
print args

我看不出有什么原因,而且我在谷歌上也没有找到答案。

这是一种语言设计选择。两种方法都不比另一种好。

Haskell可以被设计为具有任意一种main

当确实需要程序参数时,将它们作为函数参数传递给main会更方便。

当不需要程序参数时,将它们传递给main有点麻烦,因为我们需要编写更长的类型,并添加_以丢弃[String]参数。

此外,getArgs允许在程序的任何地方访问程序参数(在IO内部),而将它们只传递给main可能不太方便,因为这样就会被迫在程序中传递它们,这可能不方便。

(简短的题外话)为了它的价值,我有一个类似的反应,你很久以前,当我发现在Java中,我们有void main()而不是int main()在C.然后我意识到,在大多数程序中,我总是写return 0;在最后,所以它没有什么意义总是要求。在Java中,这是隐式的默认值,当我们确实需要返回其他东西时,我们使用System.exit()。即使这是在以前的语言(本例中是C语言)中实现的方式,新的语言也可以选择一种新的方式来实现相同的功能。

我倾向于同意chi的回答,没有明确的令人信服的理由必须这样做,所以这实际上归结为很久以前由一小群人做出的有点主观的判断。不能保证会有什么特别令人满意的理由。

这是我想到的一些理由(可能是也可能不是最初的设计师当时想到的,甚至可能不会同意)。

我们真正的爱能够做的事情是:

main :: Integer -> String -> Set Flag -> IO ()

(对于一些假设的程序,它接受一个整数、一个字符串和一组标志作为命令行参数)

能够编写小的命令行程序,就好像它们只是命令行参数的一个函数一样,这将是伟大的!但是这需要操作系统(或者至少是shell)理解Haskell程序中使用的类型,并知道如何解析它们(以及如果解析失败,或者没有足够的参数,等等),而这是不可能发生的。

也许我们可以写一个包装器来做这件事。它可以将原始字符串命令行参数解析为Haskell类型并生成错误消息(如果需要),然后为我们调用main。等等,我们完全可以做到!我们只需要将包装器命名为main(并将之前的命名为main)!

关键是:如果你想把你的程序想象成一个外部输入的简单函数,这很有意义,但是main不是那个函数main

作为一个包装器工作得更好,它处理了通过无类型接口接收输入和调用"真正是"函数的丑陋细节。您的程序。强迫您在设置代码中包含对getArgs的调用,使得处理命令行参数比仅仅访问它们更明显,并且可能促使您编写一些额外的处理代码,而不仅仅是编写main (arg1 : arg2 : _) = do stuffWith arg1 arg2

也是super将现有接口转换为您想要的接口很简单:

import System.Environment
main = real_main =<< getArgs
real_main :: [String] -> IO ()
real_main args = print args

所以你可以用你喜欢的任何方式!

相关内容

最新更新