elm / core

Elm's core libraries
http://package.elm-lang.org/packages/elm/core/latest
BSD 3-Clause "New" or "Revised" License
2.8k stars 359 forks source link

Task.andAlwaysThen proposal #1111

Open pravdomil opened 3 years ago

pravdomil commented 3 years ago

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.

github-actions[bot] commented 3 years ago

Thanks for reporting this! To set expectations:

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

dullbananas commented 3 years ago

use andThen then onError

pravdomil commented 3 years ago

show me how

avh4 commented 3 years ago
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)
pravdomil commented 3 years ago

@avh4 I think that there is following problem:

  1. task succeed
  2. andThen calls nextTask
  3. nextTask fails
  4. onError calls nextTask second time?
dullbananas commented 3 years ago

onError calls nextTask second time?

next is only executed once.

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

avhubtran commented 3 years ago

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

pravdomil commented 3 years ago

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

albertdahlin commented 3 years ago

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
pravdomil commented 3 years ago

@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