So there is this dry-rb/dry-monads library that has lots of goodies. One that is really useful for mutations is the Result monad, which has two subclasses Success and Failure.
I propose (and I can actually provide the PR) to replace Outcome with subclasses of Success and Failure, provided that:
With the previous additions, they are completely backwards-compatible, and it would be some 50 LOC.
Having Outcomes based on monads adds this optional behavior (the first one was asked in #102):
# result method with two args, provided by Dry::Monads::Result
outcome.result(
->(error) { puts "Error: #{error.inspect}" },
->(result) { puts "Result: #{result.inspect}" }
)
# `bind`, `fmap` and `or` chain other code or return the receiver, depending on success:
# bind returns the result of the block - for instance another outcome, or something else
successful_outcome.bind { |result| 1 }
# => 1
failed_outcome.bind { |result| 1 }
# => failed_outcome
# fmap wraps the result inside the same type
successful_outcome.fmap { |result| 1 }
# => Outcome::Success<value=1>
failed_outcome.fmap { |result| 1 }
# => failed_outcome
# `or` chain other code provided it's a failure:
successful_outcome.or { |result| 1 }
# => successful_outcome
failed_outcome.or { |result| 1 }
# => 1
# `or_fmap` chain other code provided it's a failure, and wraps in a success:
successful_outcome.or_fmap { |result| 1 }
# => successful_outcome
failed_outcome.or_fmap { |result| 1 }
# => Outcome::Success<value=1>
plus many more:
value_or returns the result on success, executes the block on failure
flip flips between success and failure
- All these methods accept any object responding to
call instead of a block, plus any number of additional arguments that would be appended to the block/callable.
If Mutation::Command subclasses could additionally respond to call (by aliasing it to run), they would allow constructs like:
MyCommand.(inital_args)
.bind(MyOtherCommand)
.bind(StillAnotherCommand, extra: "params")
All without breaking current code depending on run, run! and Outcome.
So there is this dry-rb/dry-monads library that has lots of goodies. One that is really useful for mutations is the Result monad, which has two subclasses
SuccessandFailure.I propose (and I can actually provide the PR) to replace Outcome with subclasses of Success and Failure, provided that:
#success?.successtoresult(with no arguments)failuretoerrors.is_a?and===will still work.With the previous additions, they are completely backwards-compatible, and it would be some 50 LOC.
Having Outcomes based on monads adds this optional behavior (the first one was asked in #102):
plus many more:
value_orreturns the result on success, executes the block on failureflipflips between success and failurecallinstead of a block, plus any number of additional arguments that would be appended to the block/callable.If Mutation::Command subclasses could additionally respond to
call(by aliasing it torun), they would allow constructs like:All without breaking current code depending on
run,run!andOutcome.