我对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
所以你可以用你喜欢的任何方式!