We will now look at different parts of the Main.hs program that we just created to understand the structure of a typical Haskell program. For convenience, the screenshot of the program is attached here:
The first line means that we are defining a module called Main. The source that follows where is contained in this module. In the absence of any specifications, all the functions defined in the module are exported, that is, they will be available to be used by importing the Main module.
The line number 3 (in the screenshot) that starts with -- is a comment. -- is used to represent a single-line comment. It can appear anywhere in the source code and comments on everything until the end of the line.
The next line is this:
main :: IO ()
This is a declaration of a function. :: is a keyword in Haskell, and you can read :: as has type. IO is a higher order data type as it takes a parameter (IO is a special data type called IO monad; we will see more of it at the later). () is an empty tuple and is a parameter to IO. An empty tuple in Haskell is equivalent to Unit Type. One can say that it is equivalent to void in imperative languages.
Hence, main :: IO () should be interpreted as follows:
main has a type IO ()
The next line actually defines the function:
main = putStrLn "Hello World"
It simply means that main is a function whose value is equivalent to an expression on the right-hand side, putStrLn "Hello World".
The putStrLn is a function defined in Prelude, and you can look up the type of the function by entering the following command in the prompt:
Prelude> :type putStrLn
putStrLn :: String -> IO ()
Here, putStrLn has a type String -> IO (). It means that putStrLn is a function that, when applied and when the argument is of String type, will have the resultant type IO (). Note how it matches with our type declaration of the main function.
The function declaration in the source code in Haskell is not compulsory, and the Haskell compiler can figure out the type of the function all by itself by looking at the definition of the function. You can try this by again editing the source file and removing declaration.
To edit the same file again, you can just issue the :edit command without any parameter. GHCi will open the editor with the previously opened file. To reload the file again, you can issue the :reload command and GHCi will load the file.
Now, you can verify the type of main function by issuing :t main (:t is equivalent to :type). Verify that the type of main is IO ().