简体   繁体   English

为什么Haskell中的主function没有任何参数?

[英]Why does the main function in Haskell not have any parameters?

I'm somewhat new to Haskell.我对 Haskell 有点陌生。 I've worked through one ore two tutorials, but I don't have much experience.我已经完成了一个或两个教程,但我没有太多经验。

Every function in Haskell is pure, this is, why we can't have any I/O without the IO-monad. Haskell 中的每个 function 都是纯粹的,这就是为什么没有 IO-monad 就不能有任何 I/O。 What I don't understand is, why do the program parameters have to be an IO action as well?我不明白的是,为什么程序参数也必须是 IO 动作? The parameters are passed to the program like to a function.参数像 function 一样传递给程序。 Why can't the parameters be accessed like in a function?为什么不能像 function 那样访问参数?

To make things clear, I don't understand, why the main function has to look like this说清楚,我不明白,为什么主要的 function 必须看起来像这样

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

Instead of this而不是这个

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

I can't see any reason for it, and I haven't found an answer googling around.我看不出有任何原因,而且我在谷歌上找不到答案。

It's a language design choice.这是一种语言设计选择。 Neither approach is strictly better than the other one.两种方法都不比另一种更好。

Haskell could have been designed to have a main of either kind. Haskell 可以设计为具有任何一种main电源。

When one does need the program arguments, it would be more convenient to have them passed as function arguments to main .当确实需要程序 arguments 时,将它们作为 function arguments 传递给main会更方便。

When one does not need the program arguments, having them passed to main is slightly cumbersome, since we need to write a longer type, and an additional _ to discard the [String] argument.当不需要程序 arguments 时,将它们传递给main有点麻烦,因为我们需要编写更长的类型,并且需要额外的_来丢弃[String]参数。

Further, getArgs lets one access the program arguments anywhere in the program (inside IO ), while having them passed to main , only, can be less convenient since one would then be forced to pass them around in the program, which can be inconvenient.此外, getArgs允许人们在程序中的任何位置(在IO内)访问程序 arguments ,虽然将它们传递给main ,但可能不太方便,因为随后将被迫在程序中传递它们,这可能很不方便。

(Short digression) For what it's worth, I had a similar reaction to yours a long time ago when I discovered that in Java we have void main() instead of int main() as in C. (题外话)对于它的价值,很久以前当我发现在 Java 中我们有void main()而不是int main()时,我和你的反应相似,就像在 C 中一样。 Then I realized that in most programs I always wrote return 0;然后我意识到在大多数程序中我总是写return 0; at the end, so it makes little sense to always require that.最后,所以总是要求它是没有意义的。 In Java that's the implicit default, and when we really need to return something else, we use System.exit() .在 Java 中,这是隐含的默认值,当我们真的需要返回其他内容时,我们使用System.exit() Even if that is the way it's done in a previous language (C, in this case), new languages can choose a new way to make available the same functionality.即使这是在以前的语言(在这种情况下为 C)中完成的方式,新的语言也可以选择一种新的方式来提供相同的功能。

I tend to agree with chi's answer, that there's no clearly compelling reason it has to be done either way, so it really comes down to a somewhat subjective judgement call that was made by a small group of people a long time ago.我倾向于同意 chi 的回答,没有明显令人信服的理由必须这样做,所以它真的归结为很久以前由一小群人做出的某种主观判断。 There's no guarantee that there is going to be any particularly satisfying reason behind it.不能保证背后会有任何特别令人满意的理由。

Here is some reasoning that comes to my mind (which may or may not have been something the original designers thought of at the time, or even would agree with).这是我想到的一些推理(这可能是原始设计师当时想到的,也可能不是,甚至会同意)。

What we're really love to be able to do is something like:我们真正喜欢做的是:

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

(for some hypothetical program that takes as command line arguments an integer, a string, and a set of flags) (对于将 arguments 和 integer、一个字符串和一组标志作为命令行的一些假设程序)

Being able to write small command line programs as if they were just a function of their command line arguments would be great, But that would need the operating system (or at least the shell) to understand the types used in a Haskell program and know how to parse them (and what to do if parsing fails, or if there aren't enough arguments, or etc).能够编写小型命令行程序,就好像它们只是命令行 arguments 的 function 一样很棒,但这需要操作系统(或至少是 shell)来理解 ZA59B783BA97FCDBB85891DFEDB2E 程序中使用的类型解析它们(以及如果解析失败,或者如果没有足够的 arguments 等,该怎么办)。 which isn't going to happen.这不会发生。

Perhaps we could write a wrapper to do that.也许我们可以编写一个包装器来做到这一点。 It could take care of parsing the raw string command line arguments into Haskell types and generating error messages (if needed), and then call main for us.它可以负责将原始字符串命令行 arguments 解析为 Haskell 类型并生成错误消息(如果需要),然后为我们调用main But wait, we can do exactly that!但是等等,我们可以做到这一点! We just have to call the wrapper main (and rename what we were previously calling main )!我们只需要调用包装器main (并重命名我们之前调用的main )!

The point is this: if you want to think of your program as a simple function of external inputs, that makes a lot of sense, but main is not that function .关键是:如果您想将您的程序视为外部输入的简单 function ,那很有意义,但main不是 function main works much better as a wrapper that takes care of the ugly details of receiving input over an untyped interface and calling the function that "really is" your program. main作为一个包装器工作得更好,它处理通过无类型接口接收输入并调用“真的是”你的程序的 function 的丑陋细节。

Forcing you to include a call to getArgs in your set up code makes it more apparent there's more to handling command line arguments than just getting access to them, and possibly nudges you to writing some of that extra handling code rather than just writing main (arg1: arg2: _) = do stuffWith arg1 arg2 .强制您在设置代码中包含对getArgs的调用,这使得处理命令行 arguments 的工作更加明显,而不仅仅是访问它们,并且可能会促使您编写一些额外的处理代码,而不仅仅是编写main (arg1: arg2: _) = do stuffWith arg1 arg2

Also, it is super trivial to convert the interface we have to the one you want:此外,将我们拥有的界面转换为您想要的界面非常简单:

import System.Environment

main = real_main =<< getArgs

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

So you can have it whichever way you prefer!所以你可以随心所欲地拥有它!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM