Generating a batched Cmd of more than one msg from Task.perform

128 views
Skip to first unread message

Austin Bingham

unread,
Oct 19, 2016, 5:51:16 AM10/19/16
to Elm Discuss
Is there a way to make Task.perform produce a batched "Cmd msg" on success (or failure, for that matter)? I've got a case where, on success, I want to send out more than one Msg, but because the success handler for Task.perform can only generate one msg this isn't straightforward.

What I'm doing now is creating an intermediate msg from the success handler. When my update function handles this intermediate msg, it is then able to generate the batched Cmd of two msgs that I want. This seems to work well, but it feels like pattern that only exists because of Task.perform's design.

So, is there a better way? Am I missing something that would let me remove this intermediate message, or is that just the way things have to work?

Rupert Smith

unread,
Oct 19, 2016, 7:11:22 AM10/19/16
to Elm Discuss
Task.perform returns a Cmd msg:

perform : (x -> msg) -> (a -> msg) -> Task x a -> Cmd msg

Cmd.batch produces a Cmd msg:

batch : List (Cmd msg) -> Cmd msg

So just have your task return a batch of commands, by using batch on a list of commands. Unless I am missing something obvious, this should be easy to accomplish?

Simon

unread,
Oct 19, 2016, 7:11:30 AM10/19/16
to Elm Discuss
Sounds like you a recursively apply the update function, and that sounds like pretty solid functional programming

Austin Bingham

unread,
Oct 19, 2016, 7:41:08 AM10/19/16
to Elm Discuss
I don't think I follow your logic. If my task produced a batch Cmd somehow (I'm not even sure how I would do that), that would still get passed to my success handler in Task.perform. That handler has to produce a single msg (i.e. not a Cmd, so batching isn't involved) which is then used by Task.perform to produce the Cmd msg. Ultimately, I don't see how anything I can do in my task can influence the single-message nature of Task.perform. 

With that said, it's entirely possible that I just misunderstand what's going on. To make things concrete, suppose that my fundamental task comes from Http.get. How would I manipulate that task (i.e. wrap it or something) to have it "return a batch of commands"? That seems like it would certainly solve address my needs!

Austin Bingham

unread,
Oct 19, 2016, 7:51:19 AM10/19/16
to Elm Discuss
Yes, my current approach does seem pretty solid from a theoretical point of view, but it feels like a poor expression of my intent. I have to create this "synthetic" intermediate msg which only exists for the purposes of the recursion, and then I have to handle the production of two messages in a different part of the code (the update function) from where I really ask for them (the call to Task.perform).

I guess what I'm getting hung up on is the fact that this is all necessitated by the design of Task.perform. What I'm trying to do may be so marginal that it doesn't make sense to try modifying Task.perform to accommodate it, and that's not really what I'm looking for anyway. I just wanted to see if there was some existing trick for doing a task-local expression of multiple msgs.

Janis Voigtländer

unread,
Oct 19, 2016, 8:03:13 AM10/19/16
to elm-d...@googlegroups.com

Why don’t you enrich your Msg type like so:

type Msg = ... | Several (List Msg)

and add a generic branch to your update function for processing a message of the Several kind (something in the spirit of: update (Several msgs) = List.foldr (... calling update recursively in an appropriate way ...) ... msgs)?

Then when you call Task.perform you make it generate a single Msg that is a Several [msg1, msg2] value. That way, you do have the “production of two messages” at the place you want it expressed.


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

Austin Bingham

unread,
Oct 19, 2016, 8:39:27 AM10/19/16
to Elm Discuss
That's substantially cleaner than my initial approach, and initial indications are that it'll work (i.e. it definitely compiles, but I need to test it out later). Thanks!
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.

Rupert Smith

unread,
Oct 19, 2016, 9:05:11 AM10/19/16
to Elm Discuss
On Wednesday, October 19, 2016 at 12:41:08 PM UTC+1, Austin Bingham wrote:
I don't think I follow your logic. If my task produced a batch Cmd somehow (I'm not even sure how I would do that)

You need to figure out how to do that. Look at the type signature of Cmd.batch - hint, it returns a single command which is actually a batch wrapper around a list of commands. 

Rupert Smith

unread,
Oct 19, 2016, 9:16:50 AM10/19/16
to Elm Discuss
Sorry, my bad. I am the one who should look more closely at the type signatures:

perform : (x -> msg) -> (a -> msg) -> Task x a -> Cmd msg

Each outcome of the task produces a 'msg' which perform then turns into a single Cmd. There is no way to tell it to produce a batch of Cmds.

Austin Bingham

unread,
Oct 19, 2016, 9:18:15 AM10/19/16
to Elm Discuss
I think I have a pretty good grasp on Cmd.batch; as you say, it's pretty clear from the signature. Where I can't connect the dots is your notion of having my Task produce a batch of commands. As far as I know (and perhaps this is what I really need to know!), the only way to turn a Task into a Cmd is via Task.perform. So given my Task which produces 'a' on success, the only lever Task.perform gives me is that I can provide a function which converts 'a' to a 'msg'. It then produces a Cmd with the msg.

So if Task.perform is my only window for creating Cmds from Tasks, how can my Task "return a batch of commands"? It seems circular to me, and "you need to figure it out" leaves me pretty much up a creek. Do you have any other hints as to how I might go about it? I feel like I'm missing some important piece of the puzzle.

Austin Bingham

unread,
Oct 19, 2016, 9:19:26 AM10/19/16
to Elm Discuss
Oops, it looks like I missed this before my last post. Sorry about that, and thanks for clearing up my confusion!
Reply all
Reply to author
Forward
0 new messages