简体   繁体   English

Haskell 中的主函数总是以 main = do 开头吗?

[英]Does the main-function in Haskell always start with main = do?

In java we always write:在java中我们总是这样写:

public static void main(String[] args){...}

when we want to start writing a program.当我们要开始编写程序时。

My question is, is it the same for Haskell, IE: can I always be sure to declare: main = do, when I want to write code for a program in Haskell?我的问题是,Haskell 和 IE 是否相同:当我想在 Haskell 中为程序编写代码时,我是否可以始终确保声明:main = do?

for example:例如:

main = do  
    putStrLn "What's your name?"  
    name <- getLine 
    putStrLn ("Hello " ++ name) 

This program is going to ask the user "What's your name?"这个程序将询问用户“你叫什么名字?” the user input will then be stored inside of the name-variable, and "Hello" ++ name will be displayed before the program terminates.然后,用户输入将存储在名称变量中,并在程序终止之前显示“Hello”++ 名称。

Short answer : No , we have to declare a main = , but not a do .简短的回答,我们必须声明一个main = ,而不是一个do

The main must be an IO monad type (so IO a ) where a is arbitrary (since it is ignored), as is written here :所述main必须是IO单子类型(因此IO a ),其中a是任意的(因为它被忽略),作为被写在这里

The use of the name main is important: main is defined to be the entry point of a Haskell program (similar to the main function in C), and must have an IO type , usually IO () . main名称的使用很重要: main被定义为 Haskell 程序的入口点(类似于 C 中的main函数),并且必须具有IO类型,通常是IO ()

But you do not necessary need do notation.但是你不需要do符号。 Actuallydo is syntactical sugar .其实do语法糖 Your main is in fact:您的main内容实际上是:

main =
    putStrLn "What's your name?" >> getLine >>= \n -> putStrLn ("Hello " ++ n)

Or more elegantly:或者更优雅:

main = putStrLn "What's your name?" >> getLine >>= putStrLn . ("Hello " ++)

So here we have written a main without do notation.所以这里我们写了一个没有do符号的main For more about desugaring do notation, see here .有关脱糖do符号的更多信息,请参见此处

Yes, if you have more than one line in your do block, and if you are even using the do notation.是的,如果你在你的多行do块,如果你甚至用do记号。

The full do -notation syntax also includes explicit separators -- curly braces and semicolons:完整的do -notation 语法还包括显式分隔符——大括号和分号:

main = do { putStrLn "What's your name?" 
          ; name <- getLine  
          ; putStrLn ("Hello " ++ name) 
          }

With them, indentation plays no role other than in coding style (good indentation improves readability; explicit separators ensure code robustness, remove white-space related brittleness).有了它们,缩进除了编码风格之外没有其他作用(良好的缩进提高可读性;显式分隔符确保代码健壮性,消除与空白相关的脆弱性)。 So when you have only one line of IO-code, like所以当你只有一行 IO 代码时,比如

main = do { print "Hello!" }

there are no semicolons, no indentation to pay attention to, and the curly braces and do keyword itself become redundant:没有分号,没有缩进需要注意,大括号和do关键字本身变得多余:

main = print "Hello!" 

So, no, not always.所以,不,并非总是如此。 But very often it does, and uniformity in code goes a long way towards readability.但很多时候确实如此,而且代码的一致性对可读性大有帮助。


do blocks translate into monadic code, but you can view this fact as implementational detail, at first. do块转换为 monadic 代码,但您可以首先将此事实视为实现细节。 In fact, you should.事实上,你应该。 You can treat the do notation axiomatically , as an embedded language, mentally.您可以将do符号公理化地视为一种嵌入式语言,在精神上。 Besides, it is that, anyway.此外,无论如何就是那样。

The simplified do -syntax is:简化的do语法是:

   do {  pattern1 <- action1
      ;  pattern2 <- action2
      .....................
      ;  return (.....)
      }

Each action i is a Haskell value of type M a i for some monad M and some result type a i .每个action i都是一个类型为M a i的 Haskell 值,用于某些 monad M和某些结果类型a i Each action produces its own result type a i while all action s must belong to the same monad type M .每个action产生自己的结果类型a i所有action s 必须属于相同的monad 类型M

Each pattern i receives the previously "computed" result from the corresponding action.每个pattern i从相应的动作接收先前“计算”的结果。

Wildcards _ can be used to ignore it.通配符_可用于忽略它。 If this is the case, the _ <- part can be omitted altogether.如果是这种情况,可以完全省略_ <-部分。


"Monad" is a scary and non-informative word, but it is really nothing more than EDSL, conceptually. “Monad”是一个可怕且没有信息量的词,但从概念上讲,它实际上只不过是 EDSL。 Embedded domain-specific language means that we have native Haskell values standing for (in this case) I/O computations .嵌入式领域特定语言意味着我们拥有代表(在这种情况下) I/O 计算的原生 Haskell 值。 We write our I/O programs in this language, which become a native Haskell value(s), which we can operate upon as on any other native Haskell value -- collect them in lists, compose them into more complex computation descriptions (programs), etc.我们用这种语言编写我们的I/O程序,它成为一个本地 Haskell 值,我们可以像对任何其他本地 Haskell 值一样对其进行操作——将它们收集在列表中,将它们组合成更复杂的计算描述(程序) , 等等。

The main value is one such value computed by our Haskell program. main值是我们的 Haskell 程序计算出的一个这样的值。 The compiler sees it, and performs the I/O program that it stands for, at run time.编译器看到它,并在运行时执行它所代表的I/O程序。

The point to it is that we can now have a "function" getCurrentTime (impossible, on the face of it, in functional paradigm since it must return different results on separate invocations), because it is not returning the current time -- the action it describes will do so, when the I/O program it describes is run by the run-time system.关键是我们现在可以有一个“函数” getCurrentTime (从表面上看,在函数范式中是不可能的,因为它必须在单独的调用中返回不同的结果),因为它没有返回当前时间——动作它描述了这样做,当它描述I / O程序被运行时系统中运行。

On the type level this is reflected by such values not having just some plain Haskell type a , but a parameterized type, IO a , "tagged" by IO as belonging to this special world of I/O programming.在类型级别,这反映在这样的值上,这些值不仅具有一些普通的 Haskell 类型a ,而且具有参数化类型IO a ,被IO “标记”为属于这个特殊的I/O编程世界。

See also: Why does haskell's bind function take a function from non-monadic to monadic .另请参阅:为什么 haskell 的 bind 函数将函数从 non-monadic 带到 monadic

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

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