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
$ 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.