Elm Language

Collecting Data: Tuples, Records and Dictionaries

Tuples

Tuples are ordered lists of values of any type.

(True, "Hello!", 42)

It is impossible to change the structure of a Tuple or update the value.

Tuples in Elm are considered a primitive data type, which means that you don’t need to import any modules to use Tuples.

Accessing values

Basics module has two helper functions for accessing values of a Tuple with a length of two ( a, b ) without using pattern matching:

fst (True, "Hello!") -- True
snd (True, "Hello!") -- "Hello!"

Access values of tuples with a bigger length is done through pattern matching.

Pattern matching

Tuples are extremely useful in combination with pattern matching:

toggleFlag: (Sting, Bool) -> (Sting, Bool)
toggleFlag (name, flag) =
    (name, not flag)

Remarks on Tuples

Tuples contain less than 7 values of comparable data type

Dictionaries

Dictionaries are implemented in a Dict core library.

A dictionary mapping unique keys to values. The keys can be any comparable type. This includes Int, Float, Time, Char, String, and tuples or lists of comparable types.

Insert, remove, and query operations all take O(log n) time.

Unlike Tuples and Records, Dictionaries can change their structure, in other words it is possible to add and remove keys.

It is possible to update a value by a key.

It is also possible to access or update a value using dynamic keys.

Accessing values

You can retrieve a value from a Dictionary by using a Dict.get function.

Type definition of Dict.get:

get : comparable -> Dict comparable v -> Maybe v

It will always return Maybe v, because it is possible to try to get a value by an non-existent key.

import Dict

initialUsers =
      Dict.fromList [ (1, "John"), (2, "Brad") ]

getUserName id =
  initialUsers
  |> Dict.get id
  |> Maybe.withDefault "Anonymous"
  
getUserName 2 -- "Brad"
getUserName 0 -- "Anonymous"

Updating values

Update operation on a Dictionary is performed by using Maybe.map, since the requested key might be absent.

import Dict

initialUsers =
  Dict.fromList [ (1, "John"), (2, "Brad") ]

updatedUsers =
  Dict.update 1 (Maybe.map (\name -> name ++ " Johnson")) initialUsers

Maybe.withDefault "No user" (Dict.get 1 updatedUsers) -- "John Johnson"

Records

Record is a set of key-value pairs.

greeter =
    { isMorning: True
    , greeting: "Good morning!"
    }

It is impossible to access a value by an non-existent key.

It is impossible to dynamically modify Record’s structure.

Records only allow you to update values by constant keys.

Accessing values

Values can not be accessed using a dynamic key to prevent possible run-time errors:

isMorningKeyName =
    "isMorning "


greeter[isMorningKeyName] -- Compiler error
greeter.isMorning -- True

The alternative syntax for accessing the value allows you to extract the value, while piping through the Record:

greeter
    |> .greeting
    |> (++) " Have a nice day!" -- "Good morning! Have a nice day!"

Extending Types

Sometimes you’d want the signature of a parameter to constrain the record types you pass into functions. Extending record types makes the idea of supertypes unnecessary. The following example shows how this concept can be implemented:

type alias Person =
    { name : String
    }


type alias Animal =
    { name : String
    }


peter : Person
peter =
    { name = "Peter" }


dog : Animal
dog =
    { name = "Dog" }


getName : { a | name : String } -> String
getName livingThing =
    livingThing.name


bothNames : String
bothNames =
    getName peter ++ " " ++ getName dog

We could even take extending records a step further and do something like:

type alias Named a = { a | name : String }
type alias Totalled a = { a | total : Int }


totallyNamed : Named ( Totalled { age : Int })
totallyNamed =
  { name = "Peter Pan"
  , total = 1337
  , age = 14
  }

We now have ways to pass these partial types around in functions:

changeName : Named a -> String -> Named a
changeName a newName =
  { a | name = newName }
  
cptHook = changeName totallyNamed "Cpt. Hook" |> Debug.log "who?"

Updating values

Elm has a special syntax for Record updates:

model =
    { id: 1
    , score: 0
    , name: "John Doe"
    }


update model =
    { model
       | score = model.score + 100
       | name = "John Johnson"
    }

This modified text is an extract of the original Stack Overflow Documentation created by the contributors and released under CC BY-SA 3.0 This website is not affiliated with Stack Overflow