Data Structures

Elm offers a number of data structures including List, Array Dict, Set, and Tuples.

Our focus will be on Records and Lists, as this is what we will encounter straight away when working with Elm.

Other structures like Tuples or Set will be handled when we need them, once we start building our application. To keep things focused we will ignore them for now.

Records

Think of records as the equivalent of objects in a JavaScript context, with the difference that all fields are defined and that you can only ask for fields that really exist. Let’s take a look at a record.

user =

{ id = 1

, user = "Foo"

, location = "Berlin"

}

It’s also advisable to create a type alias that describes the User record, because we will probably create more than one User.

type alias User =

{ id: Int

, name: String

, location: String

}

Now we can use the User alias as type signature as well as a constructor. This means we can create users by passing the needed arguments to User.

userA = User 1 "Foo" "Berlin"

userB = User 2 "Bar" "Zurich"

Accessing a field can be achieved via the dot notation.

user.id -- returns 1 : number

Alternatively we can use accessor functions that are named after the field name, .id for field id, .location for location and so on so forth.

.id user -- returns 1 : number

Finally an example showing how we can update a record field. Updating any field or fields returns a new Record obviously.

newUser = { user | location = "London" }

-- returns { id = 1, user = "Foo", location = "London" }

There is more we can do with Records, check the docs for further information and examples.

List

Creating a list can be achieved by using [] .

someList = ["a", "b", "c"] -- returns ["a","b","c"] : List String

Elm interferes with the types and tells us that we have a List containing strings. It’s important to note here that all elements have to be of the same type.

intList = [1, 2, 3, 4] -- [1,2,3,4] : List number

So we can already see it doesn’t matter what type the elements have, they only have to be of the same type. For example mixing types will lead the Elm compiler to return the following error message.

[1,2,3,4] : List number

> mixedList = ["a", 1, "b", 2]

-- TYPE MISMATCH --------------------------------------------- repl-temp-000.elm The 1st and 2nd entries in this list are different types of values. 8| ["a", 1, "b", 2]

^

The 1st entry has this type: String But the 2nd is: number

never run into unexpected values partway through. To mix different types in a

single list, create a "union type" as described in:

<http://guide.elm-lang.org/types/union_types.html> Hint: Every entry in a list needs to be the same type of value. This way younever run into unexpected values partway through. To mix different types in asingle list, create a "union type" as described in:

So we can clearly see what the problem is — via the error message. Also, this is a good example for how nice error messages are in Elm. They clearly indicate what went wrong and how to fix it. This is just one of the many benefits that come with using the language.

List offers a large number of functions to manipulate lists. Let’s go through a couple of them just to get a better of feel of what’s possible, while the official docs offer a more complete and detailed overview.

-- length returns the number of elements contained in the list

List.length [1, 2, 3, 4] -- 4 -- empty checks if the list is empty

List.isEmpty [] -- True

List.isEmpty [1] -- False -- take takes the first n members

List.take 2 [1, 2, 3] -- [1,2] -- (::) prepend to a list

0 :: [1, 2, 3] -- [0,1,2,3] -- append to a list

List.append [1, 2, 3] [4] -- [1,2,3,4] -- alternatively you can append to a list using (++) operator

[1, 2, 3] ++ [4] -- [1,2,3,4] -- check if the list contains a specified value

List.member 1 [1, 2, 3] -- True

List.member 4 [1, 2, 3] -- False

List offers more functions like drop, reverse, head and tail f.e., furthermore we have access to functions like map and filter.

List.map (\x -> x + 1) [1, 2, 3] -- [2,3,4]

So we see that map can work with anonymous functions but we can also use our previously defined add5 function to increment every element by 5.

List.map add5 [1, 2, 3] -- [6,7,8]

The list module also exposes map2, map3, map4 and map5 for functions that expect 2 or more arguments. Let’s also take a look at filter, which again works with named as well as anonymous functions.

List.filter (\x -> x > 3) [1, 2, 3, 4] -- anonymous function -> [4] gt3 x = x > 3

List.filter gt3 [1, 2, 3, 4] -- returns [4]

To round up the List section, let’s finally see how we can reduce list values. We have foldr and foldl to our disposable. While foldr reduces a list from the right, foldl does the same from the left.