6

In java we always write:

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?

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.

Will Ness
  • 62,652
  • 8
  • 86
  • 167
August Jelemson
  • 703
  • 1
  • 8
  • 23
  • 4
    `main` - yes. But `do` is a part of the body, which may or may not be there. See [here](https://www.schoolofhaskell.com/school/starting-with-haskell/basics-of-haskell/2-my-first-program#the-main-function) – Eugene Sh. Jun 23 '17 at 18:27
  • `main = putStrLn "It depends on how large 'main' is."` – atravers Feb 17 '21 at 01:28

2 Answers2

12

Short answer: No, we have to declare a main =, but not a do.

The main must be an IO monad type (so IO a) where a is arbitrary (since it is ignored), as is written here:

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 ().

But you do not necessary need do notation. Actually do is syntactical sugar. Your main is in fact:

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. For more about desugaring do notation, see here.

Willem Van Onsem
  • 321,217
  • 26
  • 295
  • 405
  • 1
    In Haskell the word "monad" refers to types (like `IO`), not values (like `main`). – Li-yao Xia Jun 23 '17 at 19:55
  • 1
    Strictly speaking, the entry point to a Haskell program must not be named `main` (you can change this by passing `-main-is `) but of course that is not the focus of the question. – user2407038 Jun 24 '17 at 00:18
  • 1
    @user2407038 Strictly speaking, is it still a Haskell program or a not-quite-Haskell program? – user253751 Jun 26 '17 at 03:38
  • The main reason to use anything other than `()` is to communicate that the program only exits either explicitly or by receiving an exception. In that case, it can an be given a polymorphic type, `IO a`. – dfeuer Mar 03 '19 at 17:30
4

Yes, if you have more than one line in your do block, and if you are even using the do notation.

The full do-notation syntax also includes explicit separators -- curly braces and semicolons:

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

main = do { print "Hello!" }

there are no semicolons, no indentation to pay attention to, and the curly braces and do keyword itself become redundant:

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. In fact, you should. You can treat the do notation axiomatically, as an embedded language, mentally. Besides, it is that, anyway.

The simplified do-syntax is:

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

Each actioni is a Haskell value of type M ai for some monad M and some result type ai. Each action produces its own result type ai while all actions must belong to the same monad type M.

Each patterni receives the previously "computed" result from the corresponding action.

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. Embedded domain-specific language means that we have native Haskell values standing for (in this case) I/O computations. 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.

The main value is one such value computed by our Haskell program. The compiler sees it, and performs the I/O program that it stands for, at run time.

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.

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.

See also: Why does haskell's bind function take a function from non-monadic to monadic.

Will Ness
  • 62,652
  • 8
  • 86
  • 167
  • Actually do notation supports 3 types of statements: Bindings (the ones with – Paul Stelian Nov 25 '20 at 01:02
  • 1
    it says "The *simplified* `do`-syntax" in the answer (emphasis added). You do not introduce something with its full specification. Sometimes best way to introduce something is with little lies even (which is also the case here because `do` works even for non-monadic values in corner cases, like `do 1`). the `do` `let` can always be rewritten as normal `let`, and the non-binding monadic value `do` statement, to a `_ – Will Ness Nov 25 '20 at 07:26
  • 1
    as for what's allowed as the last statement in a `do` block, my answer goes further and suggests always ending it with a `return ...`, as a *simplification*. which is always valid, too, thanks to the monad laws. @PaulStelian – Will Ness Nov 25 '20 at 08:18