【问题标题】:In Elm, is there a way to merge union types ? (for modularity purpose)在 Elm 中,有没有办法合并联合类型? (出于模块化目的)
【发布时间】:2017-05-11 10:13:07
【问题描述】:

从这三个声明开始:

type SharedMsg
   = SharedAction

type Page1Msg
   = Page1Action

type Page2Msg
   = Page2Action

我有办法获得以下等效项吗?喜欢“合并”联合类型的方法吗?

type Msg
   = SharedAction
   | Page1Action
   | Page2Action

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

上下文:我将 Elm 应用程序拆分为每页一个模块,每个模块都有自己的文件夹。

有些动作是共享的,有些动作是特定于页面的。

如果我要使用Html.map 方法,我觉得我必须重写页面在其自己的PageMsg 消息类型中使用的每个共享操作:

type Page1Msg
   = Page1Action
   | SharedAction

type Msg
   = Page1Msg Page1Msg
   | Page2Msg Page2Msg

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

因此我想为所有页面使用唯一的 Msg 类型,但通过在它们自己的文件夹中写入特定于页面的消息来保持模块化,然后通过合并它们以某种方式定义唯一的 Msg 类型。

【问题讨论】:

  • 这些页面是否在单页应用程序中?你有什么样的共享信息,它们是从哪里出现的?当 Elm 社区第一次尝试解决这些问题时,我在 Medium (medium.com/@alex.lew/…) 上写了一篇关于我对 Page1 和 Page2 都能够在“父”更新功能中触发一些共享消息的问题的解决方案.但从那时起,社区的思想发生了变化,了解您的案例的具体情况可能会激发出更好的解决方案!
  • (我应该提一下,如果不创建新的标签/构造函数,就无法像您尝试的那样合并联合类型。)
  • 1.感谢您关于合并类型和 2 的回答。哇超级智能翻译模式,我将朝那个方向挖掘!我想到的共享消息与您提到的那些具有相同的性质:显示全局应用加载微调器,加载跨页面共享数据...

标签: elm modularity union-types


【解决方案1】:

@z5h 的回答几乎是正确的,但类型构造函数必须有不同的名称。

您无法按照自己的方式合并类型。

至于惯用方式:您可以将拆分类型命名为 Msg,而不是 Page1Msg。所以,例如:

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

顺便记住,如果你把模块拆分成Page1.ViewPage1.Types等,那么只要暴露的功能不重叠,就可以导入不同的同名模块,即:

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

【讨论】:

  • 棘手的是这种情况是为Page1编写一个视图函数。你 Html.map 输出吗?使用什么功能?也许视图函数可以接受 SharedMsg 和 Page1Msg 构造函数作为参数?
  • Page1.view : Page1.Model -> Html Page1.Msg,来自 Main 的用法:Main.view mainModel = Html.map Page1Msg (Page1.view mainModel.page1Model)
  • 那么Page1.view是如何生成共享消息的呢?
  • Main 相同:Page1.Msg = Foo | SharedMsg Shared.Msg, Page1.view = Html.map SharedMsg (Shared.view page1Model.sharedModel)。请注意,如果您不将不合格的Page1.Msg 构造函数导入Main,则不会出现名称冲突。但是,给Page1.SharedMsg 构造函数起一个不同的名称可能会更清楚,以避免与Main.SharedMsg 混淆。
  • @AlexLew 我的看法:Shared.Model 应该驻留在Main.Model 中,作为额外参数提供给Page1.viewPage1.view : Page1.Model -> Shared.Model -> Html Page1.Msg),当你得到SharedMsgPage1.update 中,将其交给Main.update - 这意味着:Page1.update : Page1.Msg -> Page1.Model -> (Page1.Model, Cmd Page1.Msg, Maybe SharedMsg)。然后,您将在 Main.update 中响应元组的 Maybe SharedMsg 元素。
【解决方案2】:

不要忘记,您绝对没有义务完全按照基本示例中的更新视图定义进行操作。在您的情况下,您可以根据需要调整更新功能

在父母那里怎么样:

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

page1 中的更新函数有签名的地方

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

【讨论】:

    【解决方案3】:

    问题是,你说过:

    type SharedMsg
       = SharedAction
    

    所以我们知道SharedAction 的类型是SharedMsg
    但是你说:

    type Msg
       = SharedAction
       | Page1Action
       | Page2Action
    

    所以现在矛盾了,SharedActionMsg

    解决这个问题的简单方法是:

    type Msg
       = Msg SharedMsg
       | Msg Page1Msg
       | Msg Page2Msg
    

    Msg 是一个构造函数,其实例为Msg 类型,可以具有以下值。

    【讨论】:

    • 最后一个代码示例不起作用。构造函数必须具有不同的名称,即。 type A = A1 Foo | A2 Bar | A3 Baz 而不是 type A = A Foo | A Bar | A Baz
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-12
    • 2019-08-30
    • 2022-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多