Haskell/Modules
From Wikibooks, the open-content textbooks collection
[edit] Modules
Haskell modules are a useful way to group a set of related functionalities into a single package and manage a set of different functions that have the same name. The module definition is the first thing that goes in your Haskell file.
Here is what a basic module definition looks like:
module YourModule where
Note that
- The name of the module begins with a capital letter
- Each file contains only one module.
The name of the file must be that of the module but with a .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, then the file name must also start with a capital letter.
[edit] Importing
One thing your module can do is 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
-- import only the functions toLower and toUpper from Data.Char import Data.Char (toLower, toUpper) -- import everything exported from Data.List import Data.List -- import everything exported from MyModule import MyModule
Imported datatypes are specified by their name, followed by a list of imported constructors in parenthesis. For example:
-- import only the Tree data type, and its Node constructor from Data.Tree import Data.Tree (Tree(Node))
Now what to do if you import some modules, but some of them 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.
[edit] 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:
-- import everything exported from MyModule import MyModule -- import everything exported from MyOtherModule import MyOtherModule -- someFunction puts a c in front of the text, and removes all e's from the rest someFunction :: String -> String someFunction text = 'c' : remove_e text
In this case, it isn't clear which remove_e is meant. To avoid this, use the qualified keyword:
import qualified MyModule import qualified MyOtherModule someFunction text = 'c' : MyModule.remove_e text -- Will work, removes lower case e's someOtherFunction text = 'c' : MyOtherModule.remove_e text -- Will work, removes all e's someIllegalFunction text = 'c' : remove_e text -- Won't work, remove_e isn't defined.
See the difference. In this case the function remove_e isn't even defined. We call the functions from the imported modules by adding the module's name. Note that MyModule.remove_e also works if the qualified flag isn't included. The difference lies in the fact that remove_e is ambiguously defined in the first case, and undefined in the second case. If we have a remove_e defined in the current module, then using remove_e without any prefix will call this function.
| Note
There is an ambiguity between a qualified name like |
[edit] Hiding definitions
Now suppose we want to import both MyModule and MyOtherModule, 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 MyOtherModule before every call to remove_e. Can't we just not import remove_e from MyModule? The answer is: yes we can.
-- Note that I didn't use qualified this time. import MyModule hiding (remove_e) import MyOtherModule someFunction text = 'c' : remove_e text
This works. Why? Because of the word hiding on the import line. Followed by it, is a list of functions that shouldn't be imported. Hiding more than one function works like this:
import MyModule hiding (remove_e, remove_f)
Note that algebraic datatypes and type synonyms cannot be hidden. These are always imported. If you have a datatype defined in more modules, you must use qualified names.
[edit] Renaming imports
This is not really a technique to allow for overwriting, but it is often used along with the qualified flag. Imagine:
import qualified MyModuleWithAVeryLongModuleName someFunction text = 'c' : MyModuleWithAVeryLongModuleName.remove_e $ text
Especially when using qualified, this gets irritating. What we can do about it, is using the as keyword:
import qualified MyModuleWithAVeryLongModuleName as Shorty someFunction text = 'c' : Shorty.remove_e $ text
This allows us to use Shorty instead of MyModuleWithAVeryLongModuleName as prefix for the imported functions. As long as there are no ambiguous definitions, the following is also possible:
import MyModule as My import MyCompletelyDifferentModule as My
In this case, both the functions in MyModule and the functions in MyCompletelyDifferentModule can be prefixed with My.
[edit] 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:
module MyModule (remove_e, add_two) where add_one blah = blah + 1 remove_e text = filter (/= 'e') text add_two blah = add_one . add_one $ blah
In this case, only remove_e and add_two are exported. While add_two is allowed to make use of add_one, functions in modules that import MyModule cannot use add_one, as it isn't exported.
Datatype export specifications are written quite similarly to import. You name the type, and follow with the list of constructors in parenthesis:
module MyModule2 (Tree(Branch, Leaf)) where
data Tree a = Branch {left, right :: Tree a}
| Leaf a
In this case, the module declaration could be rewritten "MyModule2 (Tree(..))", declaring that all constructors are exported.
Note: 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.
[edit] Notes
In Haskell98, the last standardised version of Haskell, the module system is fairly conservative, but recent common practice consists of employing an hierarchical module system, using periods to section off namespaces.
Mutual recursive modules are possible but need some special treatment. For how to do it in GHC see: http://www.haskell.org/ghc/docs/latest/html/users_guide/separate-compilation.html#mutual-recursion
A module may export functions that it imports.
See the Haskell report for more details on the module system:

