λ1006: Prefer OrElse over Match

A Match that re-wraps the value on success and returns another monad on failure should be expressed as OrElse.

Cause

Match is called on an Option<T>, Either<L, R> or Result<T>, the result type is the same monad type as the receiver, and the success branch is the monad's Return (Option.Return, Option.Some, Either<L>.Return, Result.Return, or a lambda calling one of them).

Reason for rule

Re-wrapping the value on the success path and substituting a fallback monad on the failure path is exactly what OrElse does. The Match form is longer and hides the fact that the success case is untouched.

How to fix violations

Replace the Match call with OrElse, passing the former none/left/error argument. A code fix is available.

Examples

Disallowed

static Option<int> Example(Option<int> option, Option<int> fallback)
    => option.Match(none: fallback, some: Option.Return);

static Option<int> Example(Option<int> option, Option<int> fallback)
    => option.Match(none: () => fallback, some: x => Option.Some(x));

static Result<int> Example(Result<int> result, Result<int> fallback)
    => result.Match(ok: Result.Return, error: _ => fallback);

Allowed

static Option<int> Example(Option<int> option, Option<int> fallback)
    => option.OrElse(fallback);

static Option<int> Example(Option<int> option, Option<int> fallback)
    => option.OrElse(() => fallback);

static Result<int> Example(Result<int> result, Result<int> fallback)
    => result.OrElse(_ => fallback);

// The success branch changes the value, so this is a legitimate Match.
static Option<int> Example(Option<int> option, Option<int> fallback)
    => option.Match(none: fallback, some: x => Option.Return(x + 1));