EXPERIMENTAL

Thanks to imright_anduknowit and Enumerable_any on Reddit for their suggestions.

In Elm you don’t have a native way to list all tags in a sum type.

Let’s say we have a Fruit type defined as :

type Fruit

= Orange

| Lemon

| Apple

How can you create a list of all fruits ([Orange, Lemon, Fruit]) without missing one ?

First, let’s create a function nextFruit which given a Fruit will return a Maybe Fruit which represent the next fruit in the sum :

nextFruit : Maybe Fruit -> Maybe Fruit

nextFruit maybeCurrentFruit =

case maybeCurrentFruit of

Nothing ->

Just Orange

Just currentFruit ->

case currentFruit of

Orange ->

Just Lemon

Lemon ->

Just Apple

Apple ->

Nothing

Next, let’s create our Fruit list :

fruitList : List Fruit

fruitList =

let

buildFruitList : Maybe Fruit -> List Fruit -> List Fruit

buildFruitList maybeCurrentFruit allFruits =

case maybeCurrentFruit of

Nothing ->

allFruits

Just currentFruit ->

buildFruitList (nextFruit maybeCurrentFruit) (currentFruit :: allFruits)

in

buildFruitList (nextFruit Nothing) []

If you run fruitList you will get [Apple, Lemon, Orange].

Now, if you add Banana in Fruit, you will get a compiler error saying that the case in nextFruit doesn’t handle the Banana possibility. You’ll have to rewrite it :

nextFruit : Maybe Fruit -> Maybe Fruit

nextFruit maybeCurrentFruit =

case maybeCurrentFruit of

Nothing ->

Just Orange

Just currentFruit ->

case currentFruit of

Orange ->

Just Lemon

Lemon ->

Just Apple

Apple ->

Just Banana

Banana ->

Nothing

Ok, let’s be honest : you can make errors while writing the nextFruit function but 1/, you will be warned that a new tag has been added to the type and 2/, you can generate this code from the type declaration.

The final touch will be writing a function that given a String will return a Maybe Fruit :

fruitFromString : String -> Maybe Fruit

fruitFromString fruitString =

fruitList

|> List.filter (\x -> toString x == fruitString)

|> List.head

fruitFromString “Apple” will return Just Apple, fruitFromString “Pineapple” will return Nothing.