more flexible `to_result` on None

Currently calling to_result on None, either directly or with a block does not allow returning a Failure instance, but rather only allows you to pass a value or an array to create a tuple. I would like to open PR for a backwards compatible change that makes it more flexible, e.g.


None().to_result(Failure[:something, :something_else]) # => Failure[:something, :something_else]

# or

None().to_result { Failure[:something, :something_else] } # => Failure[:something, :something_else]

I am not sure the process for PRs to get accepted, but if I open one for discussion on github is that appropriate?

I don’t understand the use-case for this change. I make extensive use of Failure tuples like this in combination with to_result.

Quick review of tuple syntax:

Failure[:something, :something_else]

is exactly equivalent to

Failure([:something, :something_else])

therefore, when I need to convert None to a Failure tuple, I write

to_result([:something, :something_else])

The problem I see with this proposal is: if you are allowing a Result type as an argument, what happens when you write

to_result(Success[:something, :something_else])

this should be a type error IMO, because to_result is specifically meant for translating None to Failure and no other type.

I do see a possible use-case for block syntax, you might want to defer execution of that in a situation where producing the Failure is expensive, but I have not actually encountered this problem myself.

However, I would expect that the output of the block would become the inner value of the Failure, rather than accepting a Result type.

Finally, I would also like to demonstrate a monad helper that I use extensively called either. It’s an alternative to yield within an Operation object that simplifies converting error results for common things.

# Utility helper to avoid .to_monad.or {} chaining
#
# @param [#to_monad] result, Dry::Monads::Result or object that responds to `to_monad`
# @param [Dry::Monads::Result::Failure, #to_proc, { :error => Symbol }] error
#
# @example With Yield
#   user = yield fetch_user.(id).or { |err| Failure[:not_found, err] }
#
# @example With Either
#   user = either fetch_user.(id), Failure(:not_found)
#   user = either fetch_user.(id), ->(err) { Failure[:not_found, err] }
#   user = either fetch_user.(ud), error: :not_found
#
# @raise [Dry::Monads::Do::Halt]
#
# @return the unwrapped successful value
def either(result, error)
  failure =
    case error
    in { error: error_name }
      proc { |err| Failure[error_name, err] }
    in T::Procable
      error
    else
      proc { error }
    end

  Dry::Monads::Do.bind result.to_monad.or(&failure)
end

So with that helper I could also write this transformation as

either None(), Failure[:something, :something_else]