Function 在Elm中使用带嵌套更新函数的Dict.update

Function 在Elm中使用带嵌套更新函数的Dict.update,function,dictionary,elm,Function,Dictionary,Elm,我正在编写一个Elm应用程序,其中状态的主要部分位于Dict中,其中Records作为值。我有一个用于主状态模型的更新功能,以及一个用于Dict中各个记录的更新功能。是否有办法将Dict.update与记录状态更新功能一起使用 我遇到的问题是,记录的状态更新函数返回更新函数通常返回的内容:一个包含更新对象和任何要触发的命令的元组(例如(newRecord,Cmd.none))。但是,Dict.update函数需要接收记录并返回记录(例如,justnewRecord),而不是包含记录和命令对象的元

我正在编写一个Elm应用程序,其中状态的主要部分位于
Dict
中,其中
Record
s作为值。我有一个用于主状态模型的更新功能,以及一个用于
Dict
中各个记录的更新功能。是否有办法将
Dict.update
与记录状态更新功能一起使用

我遇到的问题是,记录的状态更新函数返回更新函数通常返回的内容:一个包含更新对象和任何要触发的命令的元组(例如
(newRecord,Cmd.none)
)。但是,
Dict.update
函数需要接收记录并返回记录(例如,just
newRecord
),而不是包含记录和命令对象的元组


有办法解决这个问题吗?现在,我已经使用了
Dict.get
Dict.insert
的组合,但这看起来很笨拙。

我不知道。我在我的一个项目中有这个助手函数

updateDict : comparable -> msg -> Dict comparable b -> (msg -> b -> ( b, Cmd msg )) -> (comparable -> msg -> c) -> ( Dict comparable b, Cmd c )
updateDict uid act dict fn wrapper =
    case Dict.get uid dict |> Maybe.map (fn act) of
        Just ( m, e ) ->
            ( Dict.insert uid m dict
            , Cmd.map (wrapper uid) e
            )

        Nothing ->
            ( dict, Cmd.none )

不确定这是否是您正在寻找的,但如果您的模型中有嵌套的
Dict
结构,如下所示:

type alias Model =
  { parentsAndChildren : Dict String (Dict String Int) }
update : Msg -> Model -> Model
update msg model = 
  case msg of
    NewChild parentName childName age ->
      let
        newModel =
          { model
          | parentsAndChildren =
              model.parentsAndChildren
              |> Dict.update 
                   parentName 
                   (Maybe.map insertChild)
          }

      in
        (newModel, Cmd.none)

-- helper function to update a child Dict
insertChild: String -> Int -> Dict (String Int) -> Dict (String Int)
insertChild name age childDict =
  Dict.insert name age childDict
然后,无需使子
更新
输出一个
Cmd
。您的更新可能如下所示:

type alias Model =
  { parentsAndChildren : Dict String (Dict String Int) }
update : Msg -> Model -> Model
update msg model = 
  case msg of
    NewChild parentName childName age ->
      let
        newModel =
          { model
          | parentsAndChildren =
              model.parentsAndChildren
              |> Dict.update 
                   parentName 
                   (Maybe.map insertChild)
          }

      in
        (newModel, Cmd.none)

-- helper function to update a child Dict
insertChild: String -> Int -> Dict (String Int) -> Dict (String Int)
insertChild name age childDict =
  Dict.insert name age childDict
输出
Cmd
所需的
update
功能只有顶部组件中的update功能。
因此,如果记录的更新函数始终返回
Cmd.none
,则您的子函数
update
不必输出
Cmd

,您可以简化它并仅返回更新的模型

如果应用程序体系结构不需要,子模块不必遵循
(Model,Cmd Msg)
约定

如果确实需要从较低级别传递命令,还可以重新构造子模块的
更新
功能,以简化这些更新

基于 下面是一个示例,说明如何拆分更新,以便在顶级
update
中重复使用相同的逻辑,而无需其他技巧

update:Msg->Model->(Model,Cmd-Msg)
更新msg模型=
(updateModel消息模型,updateCmd消息模型)
updateCmd:Msg->Model->Cmd Msg
updateCmd msg模型=
味精案例
更多请->
getRandomGif model.topic
_ ->
Cmd.none
更新模型:Msg->Model->Model
更新模型=
味精案例
NewGif(确定newUrl)->
Model.topic newUrl
_ ->
模型
如果您需要在
updateCmd
中更新模型,则只需传递它而不是当前模型,或者如果您愿意,甚至可以同时传递这两个模型

作为奖励,您可以完全省略case表达式中未使用的分支

使用
Dict.update
也可以在
Dict.update
中使用
updateModel
,而无需检索记录并将其写回

Dict.update childKey (Maybe.map (updateModel childMsg)) model

对于已经提供的各种答案,您能否澄清您的问题:您是否已经有一个已经生成(model,Cmd Msg)的子更新,并且您想知道如何在父更新中处理它?还是要创建一个新的子更新函数来生成(model,Cmd msg)?如果你能分享一些代码,这也会有所帮助。我已经有了一个子更新程序,想知道如何在父更新程序中处理它。看起来@halfzebra的解决方案可能是最简单的方法,但每个答案都是相关的。几乎希望我能纠正不止一个:)我完全忘记了下划线语法!需要记住的是,我可以使用它,这确实简化了很多。