Custom Types in Elm represent a fixed number of named cases. Each value corresponds to exactly one of the named cases.
A Custom Type is defined using the
type keyword and requires very little syntax. They are one of the most important techniques in Elm programming, and are used to make the possible values in code exactly match the valid values in real life, which leaves no room for invalid data, and makes impossible states impossible to represent in the code.
type Season = Spring | Summer | Autumn | Winter
Each case of a custom type can optionally have data associated with it, and different cases can have different types of data. If none of the cases have data associated with them, the discriminated union is similar to what other languages usually refer to as an enumeration (or enum).
type FlexibleNumber = Integer Int | Float Float | Invalid
Creating a value for a specific case can be done by referring to its name (
Spring), when it is defined in the same module, or is imported with the
import SeasonModule exposing (Season(..)) style syntax, or by referring to its fully qualified name (
Season.Spring) when imported with
import SeasonModule exposing (Season) style syntax.
integerTwo = Integer 2 invalid = FlexibleNumber.Invalid
Custom types, along with everything in Elm, have structural equality, which means that two values for the same case and with the same (optional) data are equivalent.
The preferred way to work with custom types is with pattern matching:
let describe flexibleNumber = case flexibleNumber of Integer i -> "Integer: " ++ fromInt(i) Float f -> "Float: " ++ fromFloat(f) Invalid -> "Invalid"
In this exercise, it's Valentine's day and you and your partner are planning on doing something nice together. Your partner has lots of ideas, and is now asking you to rate the ideas, in order to find the activity to engage in.
The following ideas are proposed by your partner:
You have six tasks to help choose your Valentine's day activity.
For each idea your partner proposes, you respond with one of three options: yes, no or maybe.
Approval Custom Type to represent these options as the following three cases:
Your partner has selected two possible restaurants: one based on the Korean cuisine and the other based on the Turkish cuisine.
Cuisine Custom Type to represent these cuisines as the following two cases:
There are tons of movies to choose from, so to narrow things down, your partner also lists their genre.
Genre Custom Type to represent the following genres as cases:
As said, your partner has come up with five different activities: playing a board game, chill out, watch a movie and go to a restaurant.
Activity Custom Type to represent these activity types:
BoardGame: no associated data.
Chill: no associated data.
Movie: has its
Genreas associated data.
Restaurant: has its
Cuisineas associated data.
Finally, you're ready to rate your partner's ideas. This is how you feel about your partner's idea:
Implement a function named
rateActivity that takes an
Activity value and returns the
Approval based on the above sentiments:
rateActivity (Restaurant Turkish) -- => Maybe