The main question I’ve seen people ask is: how do I extract a value from a union type?
Suppose you have a union type like this:
type UserId = Id Int | Uuid String
UserId value can contain either an
Int or a
String. The solution for getting to those values is simple because Elm provides only one tool for that - the
getUser : UserId -> User getUser userId = case userId of Id id -> getUserById id Uuid id -> getUserByUuid id
userId of type
UserId, we need to write a
case expression which accounts for every possible tag in the union type, and in each of those branches we can name the contained value (I called it
id in both branches) and then use it. In my case, I pass the
id to these functions:
getUserById : Int -> User getUserByUuid : String -> User
So, whenever you want to get the value in a variable of a union type, you need to write a
Another common pattern in Elm is to define new types like this:
type UserName = UserName String
This is different from defining a type alias and is a useful technique which I discuss in my upcoming book.
The interesting thing about it is that it’s not another language construct but rather a special case of union types. It’s just a regular old union type that only contains one tag - in this case
UserName, the same as the name of the type itself, which is totally cool in Elm.
How do we extract the string from a value of type
UserName? Well, we can use a
case expression like we did before:
getName : UserName -> String getName userName = case userName of UserName s -> s getName <| UserName "Joe" -- returns "Joe"
However, this does look a bit silly, so in this situation, Elm provides a convenient shortcut. We can write
getName like this instead:
getName (UserName s) = s getName <| UserName "Joe" -- returns "Joe"
Here, we are using destructuring directly in the argument list of the function in order to name the contained string.
In case you are wondering, if you try to do this when the union type has multiple tags, the compiler will complain.
Destructuring works in
let expressions as well:
toUpper : UserName -> String toUpper userName = let (UserName s) = userName in String.toUpper s
Finally, it works in anonymous functions too (there is very little difference between anonymous and named functions):
(\(UserName s) -> s) (UserName "Joe") -- returns "Joe"
There are a lot more uses for destructuring, and it’s something I also talk about in great detail in my upcoming book.
In summary, if you have a union type with multiple tags, then you need to use a
case expression to extract the contained values. If you have a single tag union type, then you can use destructuring as a shortcut when defining functions or writing
My book, Practical Elm for a Busy Developer, skips the basics and gets right into explaining how to do practical stuff. Things like building out the UI, communicating with servers, parsing JSON, structuring the application as it grows, testing, and so on. No handholding — the focus is on giving you more substance.
It’s up to date with Elm 0.19.
Pop in your email to get a sample chapter.
(You will also get notifications of new posts along with other mailing list only freebies.)