Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding elm union types

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

like image 512
Geert Olaerts Avatar asked May 04 '17 13:05

Geert Olaerts


People also ask

What is Elm type?

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.

What is custom type?

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.


Video Answer


2 Answers

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
like image 122
Alex Lew Avatar answered Sep 21 '22 17:09

Alex Lew


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.

like image 27
Matthew Walton Avatar answered Sep 20 '22 17:09

Matthew Walton