如何在 Elm 中合并多个效果?

How to merge multiple effects in Elm?

我对合并多个效果有疑问。我的目标是并行 运行 N 个命令(例如 Random 或 Http),然后合并结果并开始更新。将其视为 N 个骰子的 Elm Architecture Dice exercises 的扩展。

我知道你可以用 Task.map2 or Task.sequence 来做到这一点,但我正在寻找并行执行。

Cmd.batch听起来像我想要的并行部分,但我不知道如何合并执行结果。

这是my full Elm code 这是 how I'm guessing at transforming it to act in parallel(不起作用)。

为了它的价值,在 JS 中我会用 Promise.all

来完成这个

Promise.all([promise1, promise2, …]).then(resultsList => …)

除了这个,在网上找不到任何关于这个主题的东西,它回避了问题: and this which avoids multiple effects: . Hoping this isn't still the case: (2015 年的答案是否定的)。

Process.spawn 将允许您启动运行时 可能 交错的多个任务,但是似乎没有办法以单个 Msg a 其中 a 是一些并行任务的组合结果。

Future Plans 下“流程”页面上的注释似乎与您的问题相关。

如果您想进一步探索现在的可能性以及 spawn 的行为,我创建了一个 extension of the more-cats HTTP example app, porting some of the helpers from elm-task-extra(0.18 尚未更新)。

使用 Elm 架构,您可以使用 Cmd.batch 一次触发一堆任务,但是当结果准备就绪时,它们将作为单个 Msg 值出现在更新函数中, 并且没有保证顺序。

因此,(至少从 Elm 0.18 开始),您需要自己处理 "merging" 结果,因为您触发的 Msgs 会一个接一个地出现。在您的 Dice 示例中,您需要一个 Msg 构造函数来设置特定数组索引处的骰子值(在此示例中,我使用 Array 而不是 List 因为您将设置很多按索引):

type Msg
    = Roll
    | NewFaceAt Int Int

现在您只需要处理 update 案例中的 NewFaceAt 构造函数:

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Roll ->
            ( model
            , Cmd.batch
                (Array.toIndexedList model.dice
                    |> List.map (\( i, _ ) -> Random.generate (NewFaceAt i) (Random.int 1 6))
                )
            )

        NewFaceAt index newFace ->
            ( { model | dice = Array.set index newFace model.dice }, Cmd.none )

Here is a working example of the above on ellie-app.com.

如果您想更接近 Promise.all([...]).then(...) 示例,则必须在您的模型上加入某种状态标志,每次收到 NewFaceAt 时都会更新该标志。例如,你的骰子可能是 Maybe Int 的列表,然后当你掷骰子时,将它们全部设置为 Nothing,当骰子值出现时,你将它们设置为 Just value 然后检查查看是否所有骰子值都已填满。你可以这样写你的视图,当结果仍然未知时显示一条 "loading" 消息,并且只在所有结果都出现时才显示图像。 Here is an example that waits until all results are ready (当然,它发生得如此之快以至于您不会看到加载屏幕;在处理多个 Http 请求时效果更加明显。