We have already touched the topic of Elm’s type system briefly (for example in post VI about type annotations ) but Elm provides a few type constructs that we have not examined yet. We also talked about the advantages of having a strong type system, namely the stronger guarantees it enables as compared to dynamic languages like JavaScript. This boils down to “If it compiles, it’ll never throw a runtime exception”. In this episodes, we’ll revisit tuples and introduce type aliases and records.
About This Series
This is the ninth post in a series of short and sweet blog posts about Elm . The stated goal of this series is to take you from “completely clueless about Elm” to “chief Elm guru”, step by step. If you have missed the previous episodes, you might want to check out the table of contents .
Tuples
We have already used tuples in previous examples but since they are one of the basic building blocks for types, let’s review the concept shortly.
Tuples are similar to lists as they represent collections of multiple items. However, in a list, all elements need to have the same type. The number of elements is variable. In contrast, the elements of a tuple can all have different types but all tuples of the same type have the same length.
Here are some examples for a tuples (representing human beings with a name, weight in kilograms and their height in meters):
alice : (String, Int, Float)
alice = ("Alice", 61, 1.68)
bob : (String, Int, Float)
bob = ("Bob", 78, 1.82)
So, tuples are pairs (or triplets, quadruplets, …) of values. They are enclosed in (
and )
in Elm.
You can use pattern matching to access individual parts of the tuple. The following function takes a 3-tuple like in the example above and returns the name by doing a pattern matching on the incoming tuple. Since we do not care about the weight and the height here, we use the underscore (_
) for those values.
getName : (String, Int, Float) -> String
getName (name, _, _) = name
Type Aliases
You can assign type aliases to make your code more readable. If the first element of a tuple is meant to represent a name, why not call it just that?
type alias Name = String
type alias Weight = Int
type alias Height = Float
alice : (Name, Weight, Height)
alice = ("Alice", 61, 1.68)
bob : (Name, Weight, Height)
bob = ("Bob", 78, 1.82)
Here, we used type aliases for basic types that are provided by Elm out of the box. You can use type aliases for any type construct you like, as we’ll see later.
Records
Tuples are one way to represent data structures. They are best suited for structures with only a few attributes, like pairs of values. For more structured data, Elm offers an alternative called records. This is how records looks like:
type alias Person =
{ name : String
, weight : Int
, height : Float
}
alice : Person
alice =
{ name = "Alice"
, weight = 61
, height = 1.68
}
bob : Person
bob =
{ name = "Bob"
, weight = 78
, height = 1.82 }
Note how we used a type alias here to have an identifier for the record type. This identifier (Person
) can be used in type annotations then. The two values alice
and bob
show how to create new records.
There are a few more things that you can do with records and we will get to that in the next sections.
Access Record Attributes
Record attributes are accessed using a dot notation. To access the name of a Person
record, you would write person.name
, or person.height
to access the person’s height attribute.
The dot notation can even be used as a standalone function. This is valid Elm code which converts a list of Person
records into a list of their names:
toNames : List Person -> List String
toNames list =
List.map .name list
Update Record Fields
Elm also provides a mechanism to update records. Since all values in Elm are immutable, “updating” a record translates to creating a copy of the original record and changing one (or several) attributes in the process.
The following example demonstrates how to update one attribute.
rename : Person -> String -> Person
rename person newName =
{ person | name = newName }
The next example updates multiple attributes at once.
grow : Person -> Int -> Float -> Person
grow person weightIncrease heightIncrease =
{ person |
weight = person.weight + weightIncrease,
height = person.height + heightIncrease }
That’s it for today. Now that we have reviewed tuples, type aliases and records, there is only one major type construct missing, which is called union types. This is covered in the next episode . Check it out!
More articles
fromBastian Krol
Your job at codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
More articles in this subject area
Discover exciting further topics and let the codecentric world inspire you.
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog author
Bastian Krol
Do you still have questions? Just send me a message.
Do you still have questions? Just send me a message.