Functional programming 如何与Elm中的多态子组件通信?

Functional programming 如何与Elm中的多态子组件通信?,functional-programming,polymorphism,elm,unification,union-types,Functional Programming,Polymorphism,Elm,Unification,Union Types,我的主程序有一个更新功能 update : Msg -> Model -> ( Model, Cmd Msg ) 为了与子组件通信,我们可以添加另一个变体,并将消息包装到新消息中 type alias Model = { ... , child : Child.Model } type Msg = ... | ChildMsg Child.Msg update msg model = case msg of ...

我的主程序有一个
更新
功能

update : Msg -> Model -> ( Model, Cmd Msg )
为了与子组件通信,我们可以添加另一个变体,并将消息包装到新消息中

type alias Model =
    { ...
    , child : Child.Model
    }

type Msg
    = ...
    | ChildMsg Child.Msg

update msg model =
    case msg of
        ...

        ChildMsg childMsg ->
          let
              ( childModel, cmd ) =
                  Child.update childMsg model.child

              updatedModel =
                  { model | child = childModel }

              childCmd =
                Cmd.map ChildMsg cmd
          in
               ( updatedModel, childCmd )
但是,如果我的子组件的
update
函数的类型与父项不匹配,则这似乎很有挑战性。考虑具有多态更新功能的儿童:

-- PolymorphicChild.elm

update : Msg a -> Model -> ( Model, Cmd (Msg a) )
从该模块运行命令时,必须将其包装

PolymorphicChild.someCommand : Cmd (Msg Foo)

PolymorphicChild.someCommand
  |> Cmd.map PolymorphicChild
但是,这会产生一个
Msg(PolymorphicChild.Msg Foo)
,而不是我的应用程序所期望的
Msg PolymorphicChild.Msg

The right side of (|>) is causing a type mismatch.

(|>) is expecting the right side to be a:

    Cmd (PolyMorphicChild.Msg Foo) -> a

But the right side is:

    Cmd Polymorphic.Msg -> Cmd Msg
我尝试将多态参数添加到
App.Msg

-- App.elm

type Msg a =
   = ..
   | PolymorphicChildMsg (PolymorphicChild.Msg a) 
但它基本上毁了我的整个计划。每个涉及App.Msg的函数都需要以某种方式进行更改,以便与新的子组件一起使用


如何统一这两种类型并使这两个组件协同工作?

我认为问题在于您在公开的
Msg
类型中泄漏了太多信息。您对
Msg a
类型参数的使用似乎仅限于一组已知类型,即
作者
类别
发布
标记
。通过浏览您的代码,看起来它将永远是这四种代码中的一种,因此,您以这种方式抽象东西的事实应该保留在这个模块中,而不是公开它,并使任何其他可能导致这个问题的代码负担过重

我认为您需要将抽象向下移动一个级别,以避免将公共
Msg
类型参数化。我建议为
Msg
使用四个具体的构造函数,而不是将其参数化,并将抽象向下转换为帮助器
LoadInfo a
类型:

键入别名LoadInfo a=
{工人:工人a
,url:url
,结果:结果Http.Error(Int,列表a)
}
输入味精
=LoadPost(LoadInfo Post)
|LoadCategory(LoadInfo类别)
|LoadTag(LoadInfo标签)
|LoadAuthor(LoadInfo作者)

您能更深入地了解您想要实现的目标吗?孩子的目的是什么?可能有一种不同的方法,而不是在对象图上冒泡一个不确定类型的参数。为Wordpress制作一个Elm前端–在这一过程中有一些有趣的挑战。。。这里有一个例子来告诉你我在说什么。我不能在Ellie上发布所有内容,因为它只允许一个文件,但我认为这足以获得图片。我曾经考虑过将所有这些都放到主
应用程序中,但我希望将Wordpress后端相关的内容保留在一个单独的模块中。我对基于类型的编程还不熟悉,所以我可能在做一些愚蠢的事情……这是最近几个月来为了让新手停止思考Elm没有的“组件”而做的很多事情之一。查看“文件的生命”或“缩放Elm应用程序”以获得更好的理论基础。我仍然一直在制作类似于“子组件”的应用程序,但我尽可能长时间地使用平面结构,然后当它变得太大并且同一更新功能中有太多不相关的功能时进行重构。@wmakley感谢分享。事实上,我上周看了这两个视频,并完全根据我学到的知识重构了这个模块。没有更多的子组件:数据这看起来更好,但我如何从Http命令构造这些消息?类似于
解码器>Http.get url>Http.toTask>Task.trunt(LoadInfo-worker-url)
?这里只是简单地说,但我认为这应该可以做到:
Http.send(加载此功能有点让我大吃一惊。我将看看如何使用此技术改进我程序的其他方面。谢谢你,Chad。对于那些从
Cmd.map
角度理解它的人,甚至可以使用
Http.send(LoadInfo-worker-url)|>Cmd.map LoadPost
。函数式编程是高级的。