elm/core

Task.andAlwaysThen proposal

pravdomil opened this issue · 10 comments

Hello, I found no way how to do:

if task succeed then do task2
else if task failed then do task3

Someting like:

andThenWithResult : (Result x a -> Task x a) -> Task x a -> Task x a

Any ideas?

EDIT: Also I'm searching for andThenAlways that will do a task regardless if the task failed or not.

Thanks for reporting this! To set expectations:

  • Issues are reviewed in batches, so it can take some time to get a response.
  • Ask questions a community forum. You will get an answer quicker that way!
  • If you experience something similar, open a new issue. We like duplicates.

Finally, please be patient with the core team. They are trying their best with limited resources.

use andThen then onError

show me how

avh4 commented
andThenWithResult : (Result x a -> Task x a) -> Task x a -> Task x a
andThenWithResult next task =
    task
        |> Task.andThen (\a -> next (Ok a))
        |> Task.onError (\x -> next (Err x))

or with function composition,

andThenWithResult : (Result x a -> Task x a) -> Task x a -> Task x a
andThenWithResult next =
    Task.andThen (Ok >> next)
        >> Task.onError (Err >> next)

@avh4 I think that there is following problem:

  1. task succeed
  2. andThen calls nextTask
  3. nextTask fails
  4. onError calls nextTask second time?

onError calls nextTask second time?

next is only executed once.

  • Task.andThen only does something if the previous task was successful.
  • Task.onError only does something if the previous task failed.

edit: actually you are correct, i didn't pay attention to "nextTask fails"

ah yeah, I think you're right @pravdomil I think this could be solved still somehow using andThen/onError, but you'd also wrap the error in another Result so you could tell the difference between the original task failing and next failing. Since I don't quickly have the answer at hand for that, would you mind posting your question on Discourse https://discourse.elm-lang.org/ or asking in Elm Slack as noted by the bot "Ask questions a community forum. You will get an answer quicker that way!"

Thanks for feedback
I will leave the issue open
I think that it can be common code pattern and easy to miss the right implementation

I think this will do what you are asking for:

toResult : Task x a -> Task y (Result x a)
toResult task =
    Task.map Ok task
        |> Task.onError (Task.succeed << Err)

andThenWithResult : (Result x a -> Task x a) -> Task x a -> Task x a
andThenWithResult next task =
  toResult task
      |> Task.andThen next

@albertdahlin I think that works.

I endup using:

andAlwaysThen : (Result x a -> Task y b) -> Task x a -> Task y b
andAlwaysThen toTask a =
    a
        |> Task.map Ok
        |> Task.onError (Err >> Task.succeed)
        |> Task.andThen toTask