Is it possible to asynchronously issue HTTP requests whose results are used to update a model while concurrent updates occur?

149 views
Skip to first unread message

Paul Chiusano

unread,
Jan 30, 2015, 4:29:18 PM1/30/15
to elm-d...@googlegroups.com
I believe I need the following function for my use case, but I couldn't figure out how to do it and I suspect it's not possible. (Of course, every time I say this, Jeff tends to respond by busting out a 2-3 line implementation :)

updateAsync : (Signal (Maybe req) -> Signal (model -> model))
            -> Signal (model -> (model, Maybe req))
            -> model
            -> Signal model
updateAsync send actions model = ???

Use case is I have a UI where some actions trigger an HTTP request. When the results come back, I get a `model -> model` to be used to update the current model. While the request is being issued, other events in `actions` may come in concurrently and these should be used to update the model. Eventually each request comes back, and I want to use the `model -> model` to update the current model, which may have changed since the request was issued due to other events in `actions`.

Here's an implementation that typechecks, but is not correct:

updateAsync : (Signal (Maybe req) -> Signal (model -> model))
            -> Signal (model -> (model, Maybe req))
            -> model
            -> Signal model
updateAsync send actions model =
  let modelReqs = foldp (\a (model,_) -> a model) (model, Nothing) actions
      models = map fst modelReqs
      reqs = map snd modelReqs
      responses = send reqs
      models' = map2 (|>) models responses -- except this isn't correct
  in models'

The problem is that we need to accumulate the effects of the responses on the model, in addition to the other actions that are happening. So if model is, say, a list of strings, the request might go fetch a list of search results, and this in turn affects how a subsequent keypress is interpreted. In the above implementation, the `actions` are interpreted b `modelReqs` in a separate universe in which responses never come into the picture. Not sure if that explanation makes sense...

Any ideas? And if it's not possible, can anyone suggest a workaround for this sort of use case?

Paul :)

Jeff Smits

unread,
Jan 31, 2015, 4:35:16 AM1/31/15
to elm-discuss
Looks like this comes down to a problem of Http requests dependent on the state of the program, and the responses should influence the state of the program again. Is that the situation? Then you've run into the current problem with the Http API, which will be solved by promises in the next release. Until then you should send your requests out a port to JavaScript, do the Http there*, send the responses to another port. Then you can merge the responses (now coming as in through a port) with the actions and give that as input to foldp.

* it maybe be possible and easier to do the Http in Elm, send the responses out a port to JavaScript, the JavaScript only echoes to another port, which is your in-port. That gives you the same asynchronous loop.

--
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 elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Paul Chiusano

unread,
Jan 31, 2015, 11:48:58 AM1/31/15
to elm-discuss
Thanks, Jeff that is actually super helpful! Yes you have the description of the issue right.

I'll try out that port-based solution. That means I can't write it as a generic function, which is unfortunate, but at least I have a way of making progress.

Paul :)
You received this message because you are subscribed to a topic in the Google Groups "Elm Discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elm-discuss/hMQTNHVoMeE/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elm-discuss...@googlegroups.com.

Paul Chiusano

unread,
Feb 2, 2015, 12:05:29 PM2/2/15
to elm-d...@googlegroups.com
Unfortunately, ports don't look like they'll work very well for my use case, at least not without some major contortions. :( The issue is that the values I need to send to the port and echo back aren't a supported type - it's an ADT with some Elm functions inside. I basically would have to come up with some ad hoc encoding for this type, encode to JSON, and then do decoding of that JSON on the incoming port. That will be a lot of work for my case, and IMO is too ugly to even consider anyway.

Since in JS I will just be echoing the values sent to the port to the outgoing port, is there any way to turn of the "Customs and Border Protection"?

Paul :)
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "Elm Discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elm-discuss/hMQTNHVoMeE/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elm-discuss+unsubscribe@googlegroups.com.

Jeff Smits

unread,
Feb 2, 2015, 12:53:21 PM2/2/15
to elm-discuss

Are you sure you cannot send the http string response via JS and do the translation to the unsupported type afterwards? See also: http://stackoverflow.com/a/28278235/859279

I don't know if how easily you can change the type checks. Probably not very easily, but take a look if you like.

This method will always need annoying code massage to get the right signals defined at top-level.

To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.

Paul Chiusano

unread,
Feb 2, 2015, 1:52:10 PM2/2/15
to elm-d...@googlegroups.com
Ah, that's a good point, I do see what you're getting at. 

Unfortunately, that would *also* require some serious restructuring for my code. Right now I have a nice module of functions which internally use Http.send, but which do JSON encoding and decoding so they just look like ordinary signal transforming functions. I'd have to break apart that module and use ports, and distribute all that information elsewhere in ways that break encapsulation, etc. I'm sure it is possible, but it sounds ugly and not promising. I'm not that desperate (yet!).

It looks like my best bet is just to write a Native library, or wait around to see if 0.15 solves the problem for me, which I'm actually not sure it will.

I do really appreciate your efforts to help, though!

Paul :)

To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "Elm Discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elm-discuss/hMQTNHVoMeE/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elm-discuss...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages