I am having some troubles wrapping my head around union types in elm. I understand the simple use case like
type Visibility = All | Active | Completed
So that means that the value of Visiblity can be All, Active or Completed. So far so good. Where i get confused however is
type Msg
= OnFetchMails (WebData (List Mail))
| OnFetchSmss (WebData (List SMS))
How should i interpret this? Does it mean Msg can be of the type function OnFetchMails that takes a type function WebData that takes a list of mail? Or how should i interpret this?
I don't think that (WebData (List Mail))
is the payload?
Funny enough i can get it to work without understanding it
Advertisements. The Type System represents the different types of values supported by the language. The Type System checks validity of the supplied values, before they are stored or manipulated by the program. This ensures that the code behaves as expected.
Custom Types are models for your documents. They are the place where you define and configure fields for your content. They give structure to documents: pages, posts, articles, events, products — whatever blocks of content you need for your project.
When defining a union type, you list all the ways to construct a value of that type. In its simplest form, that definition looks like this:
type Visibility
= All
| Active
| Completed
As you've surmised, this declares the type Visibility
and defines three values, all of type Visibility
. The only way to construct a value of type Visibility
is to use one of these three options. Because of that, we often call them "constructors."
Here is a slightly more complicated union type definition:
type TrainStatus
= OnTime
| Delayed Int
As you would expect, this defines two new "constructors," OnTime
and Delayed
. But look at their types:
OnTime : TrainStatus
Delayed : Int -> TrainStatus
The OnTime
constructor takes zero arguments, and so is simply a value; it is already a TrainStatus
. But Delayed
is declared as a one-argument constructor: it is a function that creates a new TrainStatus
out of an Int
. As such, Delayed 5
, Delayed 10
, and Delayed 100
are all valid TrainStatus
values. (We can interpret them as "delayed by 5 minutes" or something similar.)
A constructor can take multiple arguments; for instance, if we'd like to include, as a String, a reason for a delay:
type TrainStatus
= OnTime
| Delayed Int String
ts : TrainStatus
ts = Delayed 20 "The conductor took a short nap."
which defines Delayed : Int -> String -> TrainStatus
.
If you're given a TrainStatus
, you can extract the Int
and String
inside of it using pattern matching:
case ts of
OnTime ->
"Your train is on time!"
Delayed minutes reason ->
"Your train has been delayed by " ++ toString minutes ++ " because " ++ reason
Actually, yes, you can think of it as a payload that goes along with each branch.
type Msg
= OnFetchMails (WebData (List Mail))
| OnFetchSmss (WebData (List SMS))
Means that a value of type Msg
can be either OnFetchMails
, which will have some value of type WebData (List Mail)
to go with it; or it can be OnFetchSmss
with a WebData (List SMS)
accompanying it.
They're sometimes called tagged unions, as they act a lot like a C-style union
construct bundled up with a tag value which says which option in the union is the currently valid one (and in fact many languages with this kind of structure in do implement them that way).
They could also be modelled as a series of subclasses of an abstract base Msg
type, adding storage for their payloads in each subclass and requiring the payloads to be provided as constructor parameters.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With