For now, we have used the definitions of the Prelude and defined our own in a test file which by default became the Main module. Haskell supports large scale development using modules and explicit export and import expressions. As a first step, we can give our test module test.hs a new name using the module construction. To be able to load the module by its module than (rather than its file name), we store the code in a file Test.hs corresponding to the module name.
module Test where fac 0 = 1 fac n = n * fac(n-1)
When we now load the module, the prompt changes to Test.
Prelude> :load Test Reading file "Test.hs": Hugs session for: /usr/share/hugs98/lib/Prelude.hs Test.hs Test> fac 5 120
We can now import the module Test from another module.
module NewTest where import Test f = fac
The import instruction makes all the public symbols of the imported module available in the importing module. Using the term "public symbols", it is clear that there must be a way to restrict the symbols exported by a module. All we need to do is place the list of exported symbols behind the name of the module.
module Test (x, y) where x = 55 y = 66 z = 77
In this (trivial) example, only the symbols x and y are exported, whereas z is only visible by the module itself. Trying to use z in another module importing Test
module NewTest where import Test a = x c = z
leads to an error:
Prelude> :load NewTest Reading file "NewTest.hs": Reading file "Test.hs": Reading file "NewTest.hs": Dependency analysis ERROR NewTest.hs:4 - Undefined variable "z"
Haskell's import directive has a number of other options such as renaming the imported module, importing just a few symbols, or enforcing the use of qualified names (such as Test.fac). The Haskell report explain the module system in detail.