Note: I’ve writing these Haskell blog posts whilst learning Haskell, so do not take them as expert guidance. I will amend the post(s) as I learn more.
Before we begin, let’s use cabal init to create a starter project, then we’ll add our code to this project as part of this post. This will create a Main.hs with the classic “Hello World” type of sample along with the Setup.hs and the .cabal file.
Modules
Apart from the simplest applications we would probably want to package functions, types etc. into modules. Modules exist in most languages, such as those in F#, TypeScript or similar to namespaces in C# & Java. In Haskell each module is stored within it’s own file and the file begins with the following declaration
module ModuleName where
Note: module names should be in PascalCase.
Obviously replacing the ModuleName with your module name and, similar to Java, the ModuleName should be made up of the path to the module file, ending with the module name. For example let’s assume we’re going to create a Calculator module and our application folder is HaskellBasics, let’s assume we’ve created a Modules folder off of this and within that a Calculator.hs file, hence the ModuleName should look like this
module Modules.Calculator where
We need to add the module to the .cabal build file using the other-modules key, for example
executable HaskellBasics
main-is: Main.hs
other-modules: Modules.Calculator
Note: We don’t include the file extension for the Calculator module.
If we add more modules then we simply add as comma separated values in the other-modules field in the .cabal file, i.e.
other-modules: Modules.Calculator, Modules.Output
To import modules into our Main.hs we use the import keyword, like this (we’re importing two modules here).
import Modules.Output
import Modules.Calculator
There’s a lot more we can do in terms of importing modules, for example importing only some functions, like this
import Modules.Calculator (add, sub)
We can also import all function except for some, essentially hiding the module functions, like this
import Modules.Calculator hiding (sub)
The ability to specify the functions available and those not available is useful to help with name clashes etc. Another way to handle such name clashes is to use the module qualified names, for example
main = print (Modules.Calculator.add 10 6)
We can also enforce qualified module names for each function within a module be importing out module like this
import qualified Modules.Calculator
and hence all uses of the functions within this module must be fully qualified.
This can end up requiring a lot more verbosity than we really want, so we can import a qualified module and alias it like this
import qualified Modules.Calculator as C
meaning we can use the function like this
main = print (C.add 10 6)
Note: The alias for the module name must start with a capital letter.