OK, here I am going for the obvious implementation again. Sorry the
formatting is a little nutty.

type Action
    = HTTPResponse String
| SomethingElse

type alias Model =
  { pendingFetches : List (Cmd msg)
  , waitingForResponse : Bool
  }


doAThing : Model -> List (Cmd Action)


update : Action -> Model -> (Model, Cmd Action)
update action model =
  case action of
    SomethingElse ->
 case (model.waitingForResponse, doAThing model) of
 (True, newFetches) ->
   ( { model | pendingFetches = model.pendingFetches ++ newFetches }
, Cmd.none )
     (False, head :: tail) ->
   ( { model
   | pendingFetches = model.pendingFetches ++ tail
   , waitingForResponse = True
}
, head )
 (False, []) ->
   ( model, Cmd.none )

    HTTPResponse value ->
      let
        newModel = processResponse value model
      in
        case newModel.pendingFetches of
          head :: tail ->
            ( { newModel | pendingFetches = tail }, head )

          [] ->
            ( { newModel | waitingForResponse = False }, Cmd.none )

On Thu, Aug 25, 2016 at 9:39 PM, Mark Hamburg <[email protected]> wrote:

> 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.
>

-- 
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.

Reply via email to