michaelbull / kotlin-result

A multiplatform Result monad for modelling success or failure operations.
ISC License
1.05k stars 63 forks source link

`orElse` for Error Type Transformation #95

Closed Hosshii closed 8 months ago

Hosshii commented 8 months ago

Hello.

Currently, Result.orElse has the following signature:

<V, E> Result<V, E>.orElse(transform: (E) -> Result<V, E>): Result<V, E>

However, it does not allow for changing the type of the error. Rust's or_else can change it, so how about modify it to align with that capability?

<T, E, F> Result<T, E>.orElse(transform: (E) -> Result<T, F>): Result<T, F>

thanks!

michaelbull commented 8 months ago

This seems like a good idea and would be a backwards-compatible change. I'm wondering if there was a reason I didn't do it like this originally - maybe Rust's reference impl wasn't always like this?

Either way seems like a good change - are there any other callsites like this that would benefit from the increased signature mapping capability?

Hosshii commented 8 months ago

I wonder too, but the Rust implementation does not seem to have changed since at least version 1.0. https://doc.rust-lang.org/1.0.0/std/result/enum.Result.html#method.or_else In Rust, unlike Kotlin, the positions of type parameters are more separated, which might be the reason for some differences. In Kotlin, all type parameters appear on one line.

<V, E, U> Result<V, E>.map(transform: (V) -> U): Result<U, E>

For Rust:

impl Result<V, E> {
    // many
    // other
    // methods
    // ...
    pub fn map<U>(self, op: fn(V) -> U) -> Result<U, E>
}

Here, T and E are declared at the block level (I replaced F for simplicity in the example, but please disregard this substitution). https://doc.rust-lang.org/std/result/enum.Result.html#method.map

I have only been able to find out about the Rust and Haskell on wiki, but besides or_else, Result.and and Result.or can also be modified similarly to Rust's and and or. It is currently as follows:

<V, E> Result<V, E>.and(result: Result<V, E>): Result<V, E>

I think the type of the success value in the argument can be made arbitrary.

<V, E, U> Result<V, E>.and(result: Result<U, E>): Result<U, E>

Similarly, Result.or

<V, E> Result<V, E>.or(result: Result<V, E>): Result<V, E>

I believe the error type can also be made arbitrary.

<V, E, F> Result<V, E>.or(result: Result<V, F>): Result<V, F>