Today I Learned

A Hashrocket project

4 posts about #elm

Destructuring Record in Fn Argument

Elm has destructuring/pattern matching that feels typical for an ML. One pattern matching feature I like is record destructuring in a function argument.

myRecord = {a = 1}

myFunc {a} = a

myFunc myRecord
# 1

Here, we destructure the key a out of the record. What’s cool about this is the record does not need to match exactly, but can be any record with the property of a.

myRecord = {a = 1, b = 2}

myFunc {a} = a

myFunc myRecord
# 1

This enables us to be able to grow the record over time without changing the signature of the function. In Elm, not having to accomodate that change across the entire program is great.

Formatting Elm Code

Elm comes with it’s own formatter.

elm-format src/

It’s got options like --upgrade which will help you get from 0.18 code to 0.19 code, and its got --validate which you can use in continuous integration to ensure all PRs are properly formatted.

In vim, formatting is enabled by default when you use elm-vim.

Where is List.zip in Elm?

unzip is a function available as part of the list package.

List.unzip [(1, 2), (3, 4)]
-- ([1,3],[2,4])

It’s defined as:

Decompose a list of tuples into a tuple of lists.

But there is no corresponding zip function to compose a tuple of lists into a list of tuples. If you just want a list to be zipped with it’s index, then you can use List.indexedMap.

List.indexedMap (\x y -> (x, y)) ["a", "b", "c"]
-- [(0,"a"),(1,"b"),(2,"c")]

And you could substitute (\x y -> (x, y)) with Tuple.pair which does the same thing.

List.indexedMap Tuple.pair ["a", "b", "c"]
-- [(0,"a"),(1,"b"),(2,"c")]

And if you don’t care about indexes but instead have two lists, you can zip those two lists together with List.map2.

List.map2 Tuple.pair [1, 3, 5] ["a", "b", "c"]
-- [(1,"a"),(3,"b"),(5,"c")]

Happy Zipping!

Random is not pure in Elm

Elm requires that functions be pure, that is, the same arguments should produce the same outputs every time. Random necessarily injects some uncertainty into what the outputs that way and Elm has decided to handle random differently than in other languages.

First, install the random package:

elm install elm/random

The Random package allows you to create numbers in a couple of different ways, but the most idiomatic is to create a generator:

generator = (Random.int 1 10)

And then create a message that will let the Elm runtime know to produce a random number with the parameters defined by the generator.

type Msg = ConsumeRandomValue

msg = Random.generate ConsumeRandomValue generator

This message can then be placed into the (model, msg) tuple that is returned from the update function. The update function is then called to respond to the message, using the message type to wrap the random value that has been produced.

import Random

type Msg = ProduceRandomValue | ConsumeRandomValue Int

update msg model =
    case msg of
        ProduceRandomValue -> 
            (model, Random.generate ConsumeRandomValue (Random.int 1 10))
        ConsumeRandomValue randomValue ->
            ({model | rValue = randomValue}, Cmd.none)