In the previous article which describes how to setup your first Elm project we already needed to import a module. Importing a module exposes its functionality in the context of the program that is loading the module. In Elm there are different ways to import modules and we will have a look at these in this article.
The Elm module system
Elm has three sources from which modules can be imported:
- The standard library
- Additionally installed modules (via the package manager)
- Custom modules from the current project
Some of the modules from the standard library are imported by default and can be used without explicitly importing them: In Elm 0.16.0 these are
The standard library covers the most essential parts of the functionality in Elm, but there is already a wide range of additional modules that can be installed via the package manager. One of them is the
elm-html package which we will use in the examples below. To import the package we first need to install it:
$ elm-package install evancz/elm-html
Before we will learn how to define custom modules let us focus on the different ways to import modules …
We are going to expand upon the Hello World example from the previous article. It already showed the simplest way of using the
import Html import Html.Attributes main : Html.Html main = Html.div [ Html.Attributes.class "wrapper" ] [ Html.h1 [ Html.Attributes.class "headline" ] [ Html.text "Hello World" ] , Html.p  [ Html.text "HTML, with qualified imports." ] ]
To generate HTML we import the
Html module and the accompanying submodule
Html.Attributes, which includes helper functions for creating HTML attributes. There is also the submodule
Html.Events for attaching event bindings to elements.
When using a qualified import one has to reference the modules functions by their fully-qualified name. This means you have to state their name including the module name and even the type of the module can only be referenced with the full qualifier (in this case
As you can see this leads to some redundancy in case a modules is used often. This brings us to the next type of imports …
Using the keyword
exposing one can define which parts of the module should be available without using the qualifier.
-- exposing single identifiers import Html exposing (Html, div, h1, p) -- exposing everything import Html.Attributes exposing (..) main : Html main = div [ class "wrapper" ] [ h1 [ class "headline" ] [ text "Hello World" ] , p  [ text "HTML, mit Unqualified Imports." ] ]
One can expose single module identifiers (module or function names, see the
Html import) or even all of the modules identifiers, as shown with the import of
Beyond the basic import functionality there is also a way of defining an alias for the imported module:
import HelperFunctions as Utils
In this example the functions defined in
HelperFunctions will be available by using
Utils as qualifier/prefix.
When to use which kind of import?
These are some best practices to consider when importing a module:
- You should try your best to use qualified imports as much as possible, as they offer the clearest way to show which module functionality is coming from.
- For often used identifiers its best though, to use an unqualified import. This prevents redundancy and helps to keep the code clean. The HTML modules are a good example for this.
- An alias should not be used to shorten module names to something meaningless and cryptic like
import Html as H. Instead one should define a suitable name that reveals the intention or the purpose of the given module.
Defining custom modules
As long as we are working in a simple app contained in a single file everything is pretty easy. In this case we do not even need a module definition as the compiler assumes we are working inside the
Main module. When projects grow, it makes sense to split them up into separate modules.
Modules get defined at the top of the file. It is optional to explicitly state what gets exported – in case this statement is left out everything will be exported, which is the same as defining the exports as
-- default module definition module Main -- custom module exporting everything module FullAwesomeness exposing (..) -- custom module exporting only the specified types and functions module Restricted exposing (ImportableType, importableFunction)
Now that we know how to import and define our own modules, let us take the next step by learning about the central construct of the Elm programming language: Functions.