Yes, a command queue is the obvious implementation for what I identified as a contrived example. The core problem, however, is how items get into the command queue through the normal command routing mechanisms.
Mark On Aug 25, 2016, at 8:18 PM, Nick H <[email protected]> wrote: >> We might generate any number of these commands during a single update call, >> but the mechanics of their execution demand that we not start the HTTP fetch >> for one until the HTTP fetch for the previous has finished. > > One solution that comes to mind is adding a command queue to your model. > Something along these lines: > > type alias Model = > { pendingFetches : List (Cmd msg) } > > update action model = > case action of > HTTPResponse value -> > let > newModel = processResponse value model > in > case newModel.pendingFetches of > head :: tail -> > ( { newModel | pendingFetches = tail }, head ) > > [] -> > ( newModel, Cmd.none ) > >> On Thu, Aug 25, 2016 at 5:51 PM, Mark Hamburg <[email protected]> wrote: >> I'm going to try to take the large app design questions and focus them on a >> more narrow and admittedly contrived example. >> >> Say the people doing the client coding needed to be able to take a URL >> string and fetch a string via HTTP. (Yes, this is covered in the HTTL >> module. Bear with me. I'm trying to keep the example simple.) Dealing with >> tasks all over the place muddies up the client architecture that would >> otherwise focus on commands for external operations. So, we define: >> >> getStringCommand : >> (Http.Error -> msg) >> -> (String -> msg) >> -> String >> -> Cmd msg >> >> This is easy to write given the standard libraries. >> >> But now it turns out we would like to execute these one at a time. We might >> generate any number of these commands during a single update call, but the >> mechanics of their execution demand that we not start the HTTP fetch for one >> until the HTTP fetch for the previous has finished. (I said it was >> contrived. Maybe we want to automatically fail subsequent commands if the >> first one fails.) >> >> From what I understand of effect managers, we could write an effect manager >> to do this but the documentation around effect managers discourages reaching >> for them as a solution. They are identified as being for library writers and >> though this serialized string-fetcher seems a bit like a library in its >> usage, it also feels like a chunk of general app functionality. Or maybe the >> backend needs to use web sockets instead of HTTP and we would like to use >> the web sockets effects manager as part of the implementation. >> >> One way to address this is to replace commands with requests, recognize >> string fetch requests when we reach a certain point in the model hierarchy, >> and process them accordingly generating commands as we move up the rest of >> the hierarchy. This has been covered in previous posts to the discussion >> list. The downside to this is that it doesn't interoperate well with code >> that wants to speak in terms of commands. One nice thing about effects >> managers is that the addressing of a command to a particular effect manager >> is essentially unseen by everything that handles it until we get to the app >> runner. Having lots of code need to switch from returning commands to >> returning requests is a very visible consequence of using this service that >> speaks via requests. >> >> Another way to handle this is by changing update functions so that they >> still speak commands, but they now have a signature like: >> >> update : Msg -> Model -> (Model, Cmd (Wrapped Msg)) >> >> We can then watch for wrapped commands and somehow unwrap the ones that >> really are looking for work by the sequencer code. That said, I'm waving my >> hands somewhat fast here and while we now continue to use commands, we don't >> use them in the way we're used to so I don't know that it's a big win over >> the requests approach. >> >> Is there a better way to do this that I'm not seeing? The example is >> contrived but so are most examples. It feels like it gets at the sort of >> problem for which there ought to be a design pattern — i.e., structure your >> types and functions like this to solve this sort of problem. >> >> Mark >> >> -- >> You received this message because you are subscribed to the Google Groups >> "Elm Discuss" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to [email protected]. >> For more options, visit https://groups.google.com/d/optout. > > -- > You received this message because you are subscribed to the Google Groups > "Elm Discuss" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "Elm Discuss" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
