In Elm, is there a way to combine union types? (for modularity purposes)

Starting with these three ads:

type SharedMsg
   = SharedAction

type Page1Msg
   = Page1Action

type Page2Msg
   = Page2Action

      

Is there a way to get the equivalent of the following? How is a way to "concatenate" join types?

type Msg
   = SharedAction
   | Page1Action
   | Page2Action

      

==============================

Context: I split my Elm application into one module per page with its own folders.

Some actions will be shared and some actions will appear on the page.

If I had to use a method Html.map

, I feel like I would have to rewrite every joint action that the page uses in its own post type PageMsg

:

type Page1Msg
   = Page1Action
   | SharedAction

type Msg
   = Page1Msg Page1Msg
   | Page2Msg Page2Msg

view : Model -> Html Msg
view =
   Html.map Page1Msg (Page1View.view model)

      

Hence, I am thinking of using a unique type Msg

for all pages, but keeping modularity by creating page specific messages in their own folders, and then defining a unique type somehow Msg

, merging them.

+3


source to share


3 answers


@ z5h's answer is almost correct, but type constructors must have different names.

You cannot combine types the way you would like.

As for the idiomatic way: you would only name the separated types Msg

, not Page1Msg

. So for example:

Page1.elm:

module Page1 exposing (Msg)

type Msg
  = Foo

      

Page2.elm:

module Page2 exposing (Msg)

type Msg
  = Bar

      



Shared.elm:

module Shared exposing (Msg)

type Msg
  = Baz

      

Main.elm:

module Main exposing (..)

import Shared
import Page1
import Page2

type Msg
  = SomethingCustom
  | SharedMsg Shared.Msg
  | Page1Msg Page1.Msg
  | Page2Msg Page2.Msg

      


By the way, remember that if you split the modules into Page1.View

, Page1.Types

etc., then as long as the public functions do not overlap, you can import different modules under the same name, that is:

import Page1.Types as Page1
import Page1.State as Page1
import Page1.View as Page1
import Page1.Decoders as Page1

      

+3


source


Remember that you are absolutely not required to follow the update type definitions in the same way as in the basic examples. In your case, you can tailor the update function to your needs

as in the parent:

update message model = 
    let 
        sharedMsgs = 
            { msg1 = Msg1 
            , msg2 = Msg2 
            }

    in case message of
        Page1Msg msg ->
            let (m, c) =
                update sharedMsgs msg model.page1
            in case c of 
                Nothing ->
                    m 
                Just c ->
                    update c m

      



where the update function on page 1 is signed

update : SharedMessages msg -> Msg -> Page1Model -> (Page1Model, Maybe msg)

      

+2


source


The problem is what you said:

type SharedMsg
   = SharedAction

      

So, we know that SharedAction

there is a type SharedMsg

.
But then you say:

type Msg
   = SharedAction
   | Page1Action
   | Page2Action

      

So now the contradiction is what SharedAction

a is Msg

.

An easy way to get around this is to say:

type Msg
   = Msg SharedMsg
   | Msg Page1Msg
   | Msg Page2Msg

      

those. Msg

is a constructor whose instances have a type Msg

that can have the following values.

0


source







All Articles