Haskell Language IO defines your program's `main` action


Example

To make a Haskell program executable you must provide a file with a main function of type IO ()

main :: IO ()
main = putStrLn "Hello world!"

When Haskell is compiled it examines the IO data here and turns it into a executable. When we run this program it will print Hello world!.

If you have values of type IO a other than main they won't do anything.

other :: IO ()
other = putStrLn "I won't get printed"

main :: IO ()
main = putStrLn "Hello world!"

Compiling this program and running it will have the same effect as the last example. The code in other is ignored.

In order to make the code in other have runtime effects you have to compose it into main. No IO values not eventually composed into main will have any runtime effect. To compose two IO values sequentially you can use do-notation:

other :: IO ()
other = putStrLn "I will get printed... but only at the point where I'm composed into main"

main :: IO ()
main = do 
  putStrLn "Hello world!"
  other

When you compile and run this program it outputs

Hello world!
I will get printed... but only at the point where I'm composed into main

Note that the order of operations is described by how other was composed into main and not the definition order.