# Result Monad
The result monad is a [[Monad]] whose generic type is a union of a success case and a failure case. See [[Railway Oriented Programming]] for using the result monad for encoding domain errors.
The result type usually comes with a `mapError` operator, making the result monad a [[Bifunctor]] as well.
## Result Monad in C# 
The `AsyncResult` is a collection of extension methods that allow a `Task<Result<>>` to be used directly as a monad. I've chosen to go this route because implementing an actual `AsyncResult` wrapper is incredibly difficult if you want it to be awaitable and also returnable from an `async` method (see [[Making an Object Awaitable]] and [[Making a Class a Valid Return From an async Method]]). Upon further consideration, I don't see any benefits for this in C#. The code below is easy to use even without a wrapper which I feel would only get in the way.
```csharp
using System;
using System.Threading.Tasks;
public record Result<T, TError>
{
    private record SuccessCase(T SuccessData) : Result<T, TError>;
    private record ErrorCase(TError ErrorData) : Result<T, TError>;
    public static Result<T, TError> Success(T value) =>
        new SuccessCase(value);
    public static Result<T, TError> Error(TError errorData) =>
        new ErrorCase(errorData);
    public static implicit operator Result<T, TError>(T v) => Success(v);
    private Result() { }
    public bool IsSuccess => this is SuccessCase;
    public TResult Either<TResult>(
        Func<T, TResult> onSuccess,
        Func<TError, TResult> onError) =>
        this switch {
            SuccessCase successCase => onSuccess(successCase.SuccessData),
            ErrorCase errorCase => onError(errorCase.ErrorData),
            _ => throw new ArgumentOutOfRangeException()
        };
    public T Force() =>
        Either(x => x, _ => throw new("Forced result out of an Error"));
}
public static class Result
{
    public static Result<T2, TError> Bind<T1, T2, TError>(
        this Result<T1, TError> m, Func<T1, Result<T2, TError>> f) =>
        m.Either(f, Result<T2, TError>.Error);
    public static Result<T2, TError> Map<T1, T2, TError>(
        this Result<T1, TError> m, Func<T1, T2> map) =>
        m.Bind<T1, T2, TError>(v => map(v));
    public static Result<T, TError2> MapError<T, TError1, TError2>(
        this Result<T, TError1> m, Func<TError1, TError2> map) =>
        m.Either(
            v => v,
            e => Result<T, TError2>.Error(map(e)));
    public static Result<IEnumerable<T2>, TError> Traverse<T1, T2, TError>(
        IEnumerable<T1> source, Func<T1, Result<T2, TError>> f)
    {
        var results = new List<T2>();
        foreach (var element in source)
        {
            var result =
                f(element).Either<Result<IEnumerable<T2>, TError>?>(
                    x =>
                    {
                        results.Add(x);
                        return null;
                    },
                    Result<IEnumerable<T2>, TError>.Error);
            if (result != null)
            {
                return result;
            }
        }
        return results;
    }
    public static Result<IEnumerable<T>, TError> Sequence<T, TError>(
        this IEnumerable<Result<T, TError>> source) =>
        Traverse(source, x => x);
    public static IEnumerable<T1> Choose<T, TError, T1>(
        this IEnumerable<Result<T, TError>> source, Func<T, T1> chooser) =>
        source
            .Select(element =>
                element.Either<T1?>(chooser, _ => default))
            .Where(value => value != null)!;
    public static IEnumerable<T> Choose<T, TError>(
        this IEnumerable<Result<T, TError>> source) =>
            Choose(source, x => x);
    public static T Get<T>(this Result<T, T> m) => m.Either(x => x, x => x);
    public static T DefaultWith<T, TError>(
        this Result<T, TError> m, Func<TError, T> defaultWith) =>
        m.MapError(defaultWith).Get();
    public static T DefaultValue<T, TError>(
        this Result<T, TError> m, T defaultValue) =>
        m.DefaultWith(_ => defaultValue);
    public static Result<T2, TError> Select<T1, T2, TError>(
        this Result<T1, TError> m, Func<T1, T2> map) =>
        m.Map(map);
    public static Result<T3, TError> SelectMany<T1, T2, T3, TError>(
        this Result<T1, TError> m,
        Func<T1, Result<T2, TError>> f,
        Func<T1, T2, T3> mapper) =>
        m.Bind(t1 => f(t1).Map(t2 => mapper(t1, t2)));
}
public static class AsyncResult
{
    public static async Task<Result<T2, TError>> Bind<T1, T2, TError>(
        this Task<Result<T1, TError>> m,
        Func<T1, Task<Result<T2, TError>>> f)
    {
        var r1 = await m;
        var r2 = await r1.Either(
            f, e => Task.FromResult(Result<T2, TError>.Error(e)));
        return r2;
    }
    public static Task<Result<T2, TError>> Map<T1, T2, TError>(
       this Task<Result<T1, TError>> m,
       Func<T1, T2> map) => m.Bind(
           v => Task.FromResult<Result<T2, TError>>(map(v)));
    public static async Task<Result<T, TError2>> MapError<T, TError1, TError2>(
        this Task<Result<T, TError1>> m,
        Func<TError1, TError2> map)
    {
        var r1 = await m;
        var r2 = r1.MapError(map);
        return r2;
    }
    public static async Task<T> Get<T>(this Task<Result<T, T>> m)
    {
        var r = await m;
        return r.Get();
    }
    public static Task<T> DefaultWith<T, TError>(
        this Task<Result<T, TError>> m, Func<TError, T> defaultWith) =>
        m.MapError(defaultWith).Get();
    public static Task<T> DefaultValue<T, TError>(
        this Task<Result<T, TError>> m, T defaultValue) =>
        m.DefaultWith(_ => defaultValue);
    public static Task<Result<T2, TError>> Select<T1, T2, TError>(
        this Task<Result<T1, TError>> m, Func<T1, T2> map) =>
        m.Map(map);
    public static Task<Result<T3, TError>> SelectMany<T1, T2, T3, TError>(
        this Task<Result<T1, TError>> m,
        Func<T1, Task<Result<T2, TError>>> f,
        Func<T1, T2, T3> mapper) =>
        m.Bind(t1 => f(t1).Map(t2 => mapper(t1, t2)));
}
```