The type alias
keyword combination gives a new name for a type, but the type
keyword in isolation declares a new type. Let's examine one of the most fundamental of these types: Maybe
type Maybe a
= Just a
| Nothing
The first thing to note is that the Maybe
type is declared with a type variable of a
. The second thing to note is the pipe character, |
, which signifies "or". In other words, something of type Maybe a
is either Just a
or Nothing
.
When you write the above code, Just
and Nothing
come into scope as value-constructors, and Maybe
comes into scope as a type-constructor. These are their signatures:
Just : a -> Maybe a
Nothing : Maybe a
Maybe : a -> Maybe a -- this can only be used in type signatures
Because of the type variable a
, any type can be "wrapped inside" of the Maybe
type. So, Maybe Int
, Maybe (List String)
, or Maybe (Maybe (List Html))
, are all valid types.
When destructuring any type
value with a case
expression, you must account for each possible instantiation of that type. In the case of a value of type Maybe a
, you have to account for both the Just a
case, and the Nothing
case:
thing : Maybe Int
thing =
Just 3
blah : Int
blah =
case thing of
Just n ->
n
Nothing ->
42
-- blah = 3
Try writing the above code without the Nothing
clause in the case
expression: it won't compile. This is what makes the Maybe
type-constructor a great pattern for expressing values that may not exist, as it forces you to handle the logic of when the value is Nothing
.