Haskell/Modules

Modules are the primary means of organizing Haskell code. We met them in passing when using  statements to put library functions into scope. Beyond allowing us to make better use of libraries, knowledge of modules will help us to shape our own programs and create standalone programs which can be executed independently of GHCi (incidentally, that is the topic of the very next chapter, ../Standalone programs/).

Modules
Haskell modules are a useful way to group a set of related functionalities into a single package and manage different functions that may have the same names. The module definition is the first thing that goes in your Haskell file.

A basic module definition looks like:

Note that
 * 1) the name of the module begins with a capital letter;
 * 2) each file contains only one module.

The name of the file is the name of the module plus the .hs file extension. Any dots '.' in the module name are changed for directories. So the module YourModule would be in the file YourModule.hs while a module Foo.Bar would be in the file Foo/Bar.hs or Foo\Bar.hs. Since the module name must begin with a capital letter, the file name must also start with a capital letter.

Importing
Modules can themselves import functions from other modules. That is, in between the module declaration and the rest of your code, you may include some import declarations such as

Imported datatypes are specified by their name, followed by a list of imported constructors in parenthesis. For example:

What if you import some modules that have overlapping definitions? Or if you import a module but want to overwrite a function yourself? There are three ways to handle these cases: Qualified imports, hiding definitions, and renaming imports.

Qualified imports
Say MyModule and MyOtherModule both have a definition for remove_e, which removes all instances of e from a string. However, MyModule only removes lower-case e's, and MyOtherModule removes both upper and lower case. In this case the following code is ambiguous:

It isn't clear which <tt>remove_e</tt> is meant! To avoid this, use the qualified keyword:

In the latter code snippet, no function named <tt>remove_e</tt> is available at all. When we do qualified imports, all the imported values include the module names as a prefix. Incidentally, you can also use the same prefixes even if you did a regular import (in our example, <tt>MyModule.remove_e</tt> works even if the "qualified" keyword isn't included).

Hiding definitions
Now suppose we want to import both <tt>MyModule</tt> and <tt>MyOtherModule</tt>, but we know for sure we want to remove all e's, not just the lower cased ones. It will become really tedious to add <tt>MyOtherModule</tt> before every call to <tt>remove_e</tt>. Can't we just exclude the <tt>remove_e</tt> from <tt>MyModule</tt>?

This works because of the word hiding on the import line. Whatever follows the "hiding" keyword will not be imported. Hide multiple items by listing them with parentheses and comma-separation:

Note that algebraic datatypes and type synonyms cannot be hidden. These are always imported. If you have a datatype defined in multiple imported modules, you must use qualified names.

Renaming imports
This is not really a technique to allow for overwriting, but it is often used along with the qualified flag. Imagine:

Especially when using qualified, this gets irritating. We can improve things by using the as keyword:

This allows us to use <tt>Shorty</tt> instead of <tt>MyModuleWithAVeryLongModuleName</tt> as prefix for the imported functions. This renaming works with both qualified and regular importing.

As long as there are no conflicting items, we can import multiple modules and rename them the same:

In this case, both the functions in <tt>MyModule</tt> and the functions in <tt>MyCompletelyDifferentModule</tt> can be prefixed with My.

Combining renaming with limited import
Sometimes it is convenient to use the import directive twice for the same module. A typical scenario is as follows:

This give access to all of the Data.Set module via the alias "Set", and also lets you access a few selected functions (empty, insert, and the constructor) without using the "Set" prefix.

Exporting
In the examples at the start of this article, the words "import everything exported from MyModule" were used. This raises a question. How can we decide which functions are exported and which stay "internal"? Here's how:

In this case, only <tt>remove_e</tt> and <tt>add_two</tt> are exported. While <tt>add_two</tt> is allowed to make use of <tt>add_one</tt>, functions in modules that import <tt>MyModule</tt> cannot use <tt>add_one</tt> directly, as it isn't exported.

Datatype export specifications are written similarly to import. You name the type, and follow with the list of constructors in parenthesis:

In this case, the module declaration could be rewritten "MyModule2 (Tree(..))", declaring that all constructors are exported.

Maintaining an export list is good practice not only because it reduces namespace pollution but also because it enables certain compile-time optimizations which are unavailable otherwise.