4
votes

Lets's say I have two type aliases:

type alias A = {...}
type alias B = {...}

and a union type

type Content = A | B

and a model type

type alias Model= {cont : Content, ...}

init : Content -> Model
init cont = {cont = cont, ...}

How do I pass a record of type A to init.

a : A
a = {...}
init a 

throws the following error:

Detected errors in 1 module.
## ERRORS in Main.elm ##########################################################

-- TYPE MISMATCH ------------------------------------------------------ Main.elm

The 1st argument to function `init` has an unexpected type.

78|               init e
                       ^
As I infer the type of values flowing through your program, I see a conflict
between these two types:

    Content

    A

I would imagine that A is a kind of "subtype" of Content. I can't just write

a:Content
a = {...}
init a

because some of the logic does case analysis on Content

1
Are the type aliases A and B, as well as the definition for Content in the same module? That fails compilation with a Duplicate Definition error. - Chad Gilbert
They aren't in the same module but i'm referencing type Content = modulename.A | modulename.B. The problem is that those types can't really be brought in to the module. I could make some kind of proxy type I suppose. What do you think? - Michiel Ariens

1 Answers

7
votes

Elm's union types are so-called discriminated unions (or tagged unions). The discriminating part is a tag or constructor. In this case I think you want:

type Content = TagA A | TagB B

Note that the first capitalised name is the tag, and anything else is other types or type variables.

Now you can do:

a : A
a = { ... }
init (TagA a)

Within init you can distinguish the two types by doing:

init content =
  case content of
    TagA a -> ...
    TagB b -> ...