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 FruitnextFruit 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 FruitfruitList =letbuildFruitList : Maybe Fruit -> List Fruit -> List FruitbuildFruitList maybeCurrentFruit allFruits =case maybeCurrentFruit ofNothing ->allFruitsJust currentFruit ->buildFruitList (nextFruit maybeCurrentFruit) (currentFruit :: allFruits)inbuildFruitList (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 FruitnextFruit 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 FruitfruitFromString fruitString =fruitList|> List.filter (\x -> toString x == fruitString)|> List.head
fruitFromString “Apple” will return Just Apple, fruitFromString “Pineapple” will return Nothing.
You can generalize fruitList :
enumList : (Maybe a -> Maybe a) -> List aenumList nextEnumFn =letbuildEnumList : Maybe a -> List a -> List abuildEnumList maybeCurrentEnum allEnums =case maybeCurrentEnum ofNothing ->allEnumsJust currentEnum ->buildEnumList (nextEnumFn maybeCurrentEnum) (currentEnum :: allEnums)inbuildEnumList (nextEnumFn Nothing) []
Hacker Noon is how hackers start their afternoons. We’re a part of the @AMIfamily. We are now accepting submissions and happy to discuss advertising & sponsorship opportunities.
To learn more, read our about page, like/message us on Facebook, or simply, tweet/DM @HackerNoon.
If you enjoyed this story, we recommend reading our latest tech stories and trending tech stories. Until next time, don’t take the realities of the world for granted!