Composing a Task with a function that returns a Cmd

Say I have a function doSomething : a -> Cmd b and another getArgument : Task x a. Can I combine them to get a single Cmd b?

Classic example would be getting current time with and passing it to a function Time.Posix -> Cmd b. In my case I want to use timestamp in the name of a file downloaded with File.Download.string.

If doSomething would return a Task x b I could do

    |> Task.andThen doSomething 
    |> Task.attempt handleResult

Is there a way to compose the Task and a function returning a Cmd? Or do I always need two Msgs an two updates - first to get a and then to pass it to the doSomething and return a Cmd b?

You could write a “Helper-message” that could look like this:

type Msg =
   | GetTimeFor (Time.Posix -> Msg)
   | SaveToFile String Time.Posix

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
   case msg of
      GetTimeFor toMsg->
         (model, Task.perform toMsg

Didn’t check if this compiles, but does it make sense? :sunny:

you would send the message like GetTimeFor (SaveToFile "hello bro")

I think it’s quite nice that GetTimeFor is now reusable wherever you may need it!


Neat idea @opsvager, I had never considered a recursive Msg type like that before. :+1:

1 Like

Note that there are drawbacks to storing functions in your Msg type (same problems also apply to the Model type) Implications of storing functions in model or msg type


Agreed - these kinds of tricks comes at a cost. Alternatively, you could make a specialized GetTimeForSaveFile-message, without the type-parameter. It feels “dumber”, but it’s probably the best approach :sunny:

A similar but slightly different approach

init : () -> ( Model, Cmd Msg )
init _ =
    ( ()
        |> timeToCmd
        |> Task.perform RunCmd

type Msg
    = RunCmd (Cmd Msg)
    | ...

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        RunCmd cmd ->
            ( model, cmd )

Someone can correct me if I’m wrong about this but I believe storing Cmd or Task in your Msg/Model has the same drawbacks as storing functions.

I believe most likely it does. Cmd.none == Cmd.none does work but trying to compare commands in general will result in an error.

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.