Skip to content

Modules

Simply put, in Haskell, a module is a source code file. These modules can be

  • Part of our own project,
  • Part of the standard library or
  • Part of a third-party package we installed.

The manner in which we use data types, type classes, and functions defined in a module is the same in each of these cases.

Module Names

The name of a module must start with an uppercase letter, as in MyFancyModule.

Module names can be composed of multiple components separated by periods, as in Control.Monad.Reader. In this case, each component must follow the rule that it starts with an uppercase letter.

Association Between Module Names and Files

With one exception discussed below, module names correspond to file names relative to some root directory. When breaking up our own project into multiple modules, the root directory is the the root directory of our project. We'll discuss how to define projects using stack later in this chapter. For modules that are part of the standard library or of a third-party package, the root directory is wherever the standard library or the third-party package is installed. Of course, the compiler needs to find these files when we try to compile our code and our code imports some of these modules. To this end, GHC has a default location where the standard library and third-party packages are installed. In this course, we use stack to manage our projects. stack defines a sandbox for each project. Packages on which our project depends are installed in a specific location within our project, and stack configures GHC to look for third-party packages within this project-specific location.

If a module has the name MyFancyModule, then this module corresponds to the source code file MyFancyModule.hs in the root directory of the package it is part of. For modules with names made up of multiple components, the last component determines the file name. The components that come before it determine the hierarchy of directories where this file is stored. For example, the Control.Monad.Reader module is found in the file Reader.hs contained in the Monad folder, which is contained in the Control folder, which is contained in the root directory of the package that provides the Control.Monad.Reader module (the mtl package in this case).

Module Headers

With one exception, every source code file must start with a module header. This header simply defines the name of the module. For MyFancyModule, the header is

module MyFancyModule where

-- all the types, type classes, and functions defined in the module

For modules whose names have multiple components, the module header needs to list the full name of the module:

module Control.Monad.Reader where

-- all the types, type classes, and functions defined in the module

Module Headers and File Names Must Match

We already learned that we can import modules using the import keyword. For example,

import Control.Monad.Reader

When we do this, GHC looks for the file Control/Monad/Reader.hs in the root directory of our own project and in the root directories of all packages specified as dependencies of our project. It then inspects the module header of this file to see whether the name of the module in this file actually matches the module we are trying to import. If it doesn't, GHC reports an error and refuses to proceed.

A Special Module: Main

When building complete programs in Haskell, GHC needs to know where the execution of our program should start. Just as every Java program has a main method, and every C, C++ or Rust program has a main function, every Haskell program has a main function of type

main :: IO ()

In other words, our entire program is just one giant IO action that does not take any arguments and does not return anything.

This function must be defined in a module called Main. It is customary to call the source code file containing the Main module Main.hs, because this makes it easy for a reader of our program to identify the entry point of our program. However, this is not required. The file containing the Main module can be any .hs file. When using stack to build our project, the project configuration file package.yaml, which we will discuss in more detail soon, specifies which file in our project is to be used as the Main module.

No matter the name of the source code file containing the Main module, it is still good practice to start this source code file with the header

module Main where

However, we do not have to do this. In our implementation of the display program earlier, for example, we simply placed some Haskell code into the file display.hs, including a main function, but we did not provide a module header. We compiled this program using

Shell
$ stack ghc display.hs
[1 of 1] Compiling Main             ( display.hs, display.o )
Linking display ...

The important part is

[1 of 1] Compiling Main             ( display.hs, display.o )

This says that GHC is compiling the Main module, which it found in the file display.hs. So, if there is no module header, GHC treats the file being compiled as the Main module.