core icon indicating copy to clipboard operation
core copied to clipboard

Task.andAlwaysThen proposal

Open pravdomil opened this issue 3 years ago • 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.

pravdomil avatar May 26 '21 13:05 pravdomil

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.

github-actions[bot] avatar May 26 '21 13:05 github-actions[bot]

use andThen then onError

dullbananas avatar May 26 '21 13:05 dullbananas

show me how

pravdomil avatar May 26 '21 13:05 pravdomil

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 avatar May 26 '21 18:05 avh4

@avh4 I think that there is following problem:

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

pravdomil avatar May 26 '21 22:05 pravdomil

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"

dullbananas avatar May 26 '21 23:05 dullbananas

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!"

avhubtran avatar May 27 '21 00:05 avhubtran

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

pravdomil avatar May 30 '21 08:05 pravdomil

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 avatar Aug 02 '21 16:08 albertdahlin

@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

pravdomil avatar Aug 04 '21 11:08 pravdomil