2017-07-30 50 views
0

我有一個關於合併多個效果的問題。我的目標是並行運行N個命令(例如Random或Http),然後合併結果並啓動更新。把它想象成N個骰子Elm Architecture Dice exercises的延伸。如何在Elm中合併多個效果?

我知道您可以使用Task.map2Task.sequence來做到這一點,但我特別關注並行執行。

Cmd.batch聽起來像我想要的並行部分,但我無法弄清楚如何合併執行結果。

Here's my full Elm code and here's how I'm guessing at transforming it to act in parallel(does not work)。 How to perform multiple Http requests (Tasks) in bulk in Elm lang這避免了多次:

對於它的價值,在JS我會用Promise.all

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

無法找到有關這個主題的東西在網上,除了這一點,它迴避了問題,做到這一點效果:How do I add a second die to this elm effects example?。希望這不是這種情況:Is there parallelism in Elm?(2015答案是否定的)。

回答

1

使用Elm Architecture,您可以使用Cmd.batch一次性啓動一堆任務,但是當結果準備就緒後,它們將作爲更新函數中的單個Msg值進入,並且不會保證順序。

因此,(至少從榆樹0.18開始),您需要自己處理「合併」結果,因爲您發起的Msgs會一個接一個。在你的骰子例如,你想一個Msg構造函數在特定的數組索引設置(在這個例子中,我使用Array代替List因爲你會設置很多的指數)一個骰子值:

type Msg 
    = Roll 
    | NewFaceAt Int Int 

現在你只需要來處理NewFaceAt構造在update案件:

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,然後檢查是否填充了所有骰子值。您可以用這種方式編寫視圖,以便在結果仍然未知時顯示「加載」消息,並且僅在所有結果都處於顯示狀態時才顯示圖像。Here is an example that waits until all results are ready(授予它的速度非常快,您將看不到加載屏幕;處理多個Http請求時效果更明顯)。

1

Process.spawn將允許您揭開序幕的是,運行時可能交織,但似乎沒有辦法用一個單一的Msg a落得多個任務,其中a是多個並行任務的一些綜合作用的結果一起。

Future Plans下的Process頁面上的註釋看起來與您的問題有關。

如果您想進一步探索什麼是現在可以和spawn行爲,我創建了一個extension of the more-cats HTTP example app,移植一些傭工從elm-task-extra(尚未0.18更新)。

相關問題