Modules
Defining Your Own Module
Section titled “Defining Your Own Module”If we have a file called Business.hs, we can define a Business module that can be import-ed, like so:
module Business ( Person (..), -- ^ Export the Person type and all its constructors and field names employees -- ^ Export the employees function) where-- begin types, function definitions, etcA deeper hierarchy is of course possible; see the Hierarchical module names example.
Exporting Constructors
Section titled “Exporting Constructors”To export the type and all its constructors, one must use the following syntax:
module X (Person (..)) whereSo, for the following top-level definitions in a file called People.hs:
data Person = Friend String | Foe deriving (Show, Eq, Ord)
isFoe Foe = TrueisFoe _ = FalseThis module declaration at the top:
module People (Person (..)) wherewould only export Person and its constructors Friend and Foe.
If the export list following the module keyword is omitted, all of the names bound at the top level of the module would be exported:
module People wherewould export Person, its constructors, and the isFoe function.
Importing Specific Members of a Module
Section titled “Importing Specific Members of a Module”Haskell supports importing a subset of items from a module.
import qualified Data.Stream (map) as Dwould only import map from Data.Stream, and calls to this function would require D.:
D.map odd [1..]otherwise the compiler will try to use Prelude’s map function.
Hiding Imports
Section titled “Hiding Imports”Prelude often defines functions whose names are used elsewhere. Not hiding such imports (or using qualified imports where clashes occur) will cause compilation errors.
Data.Stream defines functions named map, head and tail which normally clashes with those defined in Prelude. We can hide those imports from Prelude using hiding:
import Data.Stream -- everything from Data.Streamimport Prelude hiding (map, head, tail, scan, foldl, foldr, filter, dropWhile, take) -- etcIn reality, it would require too much code to hide Prelude clashes like this, so you would in fact use a qualified import of Data.Stream instead.
Qualifying Imports
Section titled “Qualifying Imports”When multiple modules define the same functions by name, the compiler will complain. In such cases (or to improve readability), we can use a qualified import:
import qualified Data.Stream as DNow we can prevent ambiguity compiler errors when we use map, which is defined in Prelude and Data.Stream:
map (== 1) [1,2,3] -- will use Prelude.mapD.map (odd) (fromList [1..]) -- will use Data.Stream.mapIt is also possible to import a module with only the clashing names being qualified via import Data.Text as T, which allows one to have Text instead of T.Text etc.
Hierarchical module names
Section titled “Hierarchical module names”The names of modules follow the filesystem’s hierarchical structure. With the following file layout:
Foo/├── Baz/│ └── Quux.hs└── Bar.hsFoo.hsBar.hsthe module headers would look like this:
-- file Foo.hsmodule Foo where
-- file Bar.hsmodule Bar where
-- file Foo/Bar.hsmodule Foo.Bar where
-- file Foo/Baz/Quux.hsmodule Foo.Baz.Quux whereNote that:
- the module name is based on the path of the file declaring the module
- Folders may share a name with a module, which gives a naturally hierarchical naming structure to modules
Syntax
Section titled “Syntax”Remarks
Section titled “Remarks”Haskell has support for modules:
On the consumer end of a module, one can:
haskell.org has a great chapter on module definition.