Skip to content

Instantly share code, notes, and snippets.

@SaahilClaypool
Last active June 21, 2022 01:37
Show Gist options
  • Save SaahilClaypool/978f93f6a23ca5167ce7f24542c7fa73 to your computer and use it in GitHub Desktop.
Save SaahilClaypool/978f93f6a23ca5167ce7f24542c7fa73 to your computer and use it in GitHub Desktop.
EitherMaybe
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