如何在 Elm 中进行适当的继承?

How to do proper inheritance in Elm?

我正在制作一个可以包含类型 A 或类型 B 的项目的待办事项列表。所以我制作了一个类型 Item,即 AB。该模型包含一个 ItemModel 列表和一个整数,我们用它来为每个待办事项分配一个 id。

module Feed where

import A
import B

-- MODEL

type Item = A | B
type ItemModel = A.Model | B.Model

type alias Id = Int

type alias Model = 
    { todo : List (Id, ItemModel)
    , nextCount : Id}

init : Model
init = Model [] 0

下面的函数用于通过使用 Id.

查找来更新模型中的 ItemModel
updateItem : (ItemModel -> ItemModel) -> Id -> Model -> Model
updateItem f id model =
  let test (id', x) = (id', if id == id' then f x else x)
  in Model (List.map test model.todo) model.nextCount 

麻烦从这里开始。我不知道如何使用已调用操作的项目的更新功能。 Item.update 不起作用,因为它不存在。

-- UPDATE

type Action = SubAction Id Item.Action

update : Action -> Model -> Model
update action model =
  case action of
    SubAction id action ->
      updateItem (Item.update action) id model

我也无法显示我的列表,我知道 Item.view 不起作用,但它是为了说明我的想法。如果 f.e,则代码有效。我使用 A.view 并有 todo : List (Id, A.Model),但我希望它适用于 AB。我该如何解决这个问题?

-- VIEW

view : Signal.Address Action -> Model -> Html
view address model =
  let view' (id, x) = Item.view (Signal.forwardTo address <| SubAction id) x
      lstTodo = List.map view' model.todo
  in Html.div [] lstTodo

首先,最好使用 Dict,而不是 List (Id, ItemModel)

然后只是模式匹配(代码未经测试):

type Item = ItemA A.Model | ItemB B.Model
type Action = SubActionA Id A.Action | SubActionB Id B.Action | ...

updateA : A.Action -> Item -> Item
updateA action model = case model of
  ItemA model -> ... -- we have an A item here, do something
  Nothing -> ... -- there's a B item here, app logic must be wrong somewhere

updateB : B.Action -> Item -> Item
updateB action model = case model of
  ItemB model -> ... -- we have a B item here, do something
  Nothing -> ... -- there's an A item here, app logic must be wrong somewhere

update : Action -> Model -> Model
update action model =
  case action of
    SubActionA id action -> { model | todo = Dict.update id (Maybe.map (updateA action)) model.todo }
    SubActionB id action -> { model | todo = Dict.update id (Maybe.map (updateB action)) model.todo }

updateA/B action 在这里被柯里化 - 所以类型是 ItemModel -> ItemModel.

另请注意,Maybe.map 将函数 a -> b 映射到 Maybe a -> Maybe b - 正是 Dict.update 所期望的!

同样在视图中:

case model of
  ItemA model -> A.view model
  ItemB model -> B.view model

如需进一步参考 - 请阅读 this,尤其是有关标记联合的部分。