Last active
June 21, 2022 01:37
-
-
Save SaahilClaypool/978f93f6a23ca5167ce7f24542c7fa73 to your computer and use it in GitHub Desktop.
EitherMaybe
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public struct Maybe<T> | |
{ | |
private readonly T _value; | |
public T Value { get => IsSome ? _value : throw new NullReferenceException(); } | |
public bool IsSome { get; set; } | |
public Maybe() | |
{ | |
IsSome = false; | |
_value = default!; | |
} | |
public Maybe(T value) | |
{ | |
IsSome = true; | |
_value = value; | |
} | |
public static implicit operator Maybe<T>(T value) => value == null ? new() : new(value); | |
public static implicit operator Maybe<T>(None _) => new(); | |
} | |
public struct None { } | |
public static class Maybe | |
{ | |
public readonly static None None = new(); | |
public static X Match<T, X>(this Maybe<T> maybe, Func<T, X> some, Func<X> none) => | |
maybe.IsSome ? some(maybe.Value) : none(); | |
public static T Or<T, X>(this Maybe<T> maybe, T or) => | |
maybe.IsSome ? maybe.Value : or; | |
public static T Or<T, X>(this Maybe<T> maybe, Func<T> or) => | |
maybe.IsSome ? maybe.Value : or.Invoke(); | |
} | |
public struct Either<T, E> | |
{ | |
private readonly T _value; | |
private readonly E _error; | |
public T Value { get => IsOk ? _value : throw new NullReferenceException(); } | |
public E Error { get => !IsOk ? _error : throw new NullReferenceException(); } | |
public bool IsOk { get; set; } | |
public Either(bool isOk, T value, E error) | |
{ | |
IsOk = isOk; | |
_value = value; | |
_error = error; | |
} | |
public static implicit operator Either<T, E>(T value) => | |
value == null ? throw new NullReferenceException() : new(true, value, default!); | |
public static implicit operator Either<T, E>(Failure<E> fail) => new(false, default!, fail.Value); | |
} | |
public struct Failure<T> | |
{ | |
public T Value { get; set; } | |
public Failure(T value) => Value = value; | |
} | |
public static class Either | |
{ | |
public static Failure<T> Fail<T>(T value) => new(value); | |
public static Either<T, Exception> Try<T>(Func<T> func) | |
{ | |
try | |
{ | |
return func(); | |
} | |
catch (Exception ex) | |
{ | |
return Fail(ex); | |
} | |
} | |
public static X Match<T, E, X>(this Either<T, E> either, Func<T, X> ok, Func<E, X> fail) => | |
either.IsOk ? ok(either.Value) : fail(either.Error); | |
public static T Or<T, E>(this Either<T, E> either, T or) => | |
either.IsOk ? either.Value : or; | |
public static T Or<T, E>(this Either<T, E> either, Func<T> or) => | |
either.IsOk ? either.Value : or.Invoke(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment