Last active
July 21, 2021 13:58
-
-
Save htsign/0c62e3776085454254ef268bbf851903 to your computer and use it in GitHub Desktop.
simple C# Option(Maybe) MonadLike implementation
This file contains 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 static class Option | |
{ | |
public static Option<T> Create<T>(T? value) => value != null ? new Some<T>(value) : Option<T>.None; | |
public static None<dynamic> None { get; } = new None<dynamic>(); | |
} | |
public abstract class Option<T> : IEquatable<Option<T>> | |
{ | |
public static Option<T> None { get; } = new None<T>(); | |
public abstract bool IsSome { get; } | |
public abstract bool IsNone { get; } | |
public abstract Option<U> Select<U>(Func<T, U> f); | |
public abstract Option<T> Where(Func<T, bool> f); | |
public abstract Option<U> SelectMany<U>(Func<T, Option<U>> f); | |
public abstract Option<V> SelectMany<U, V>(Func<T, Option<U>> f, Func<T, U, V> g); | |
public abstract T OrDefault(T defaultValue); | |
public abstract T OrDefault(Func<T> defaultFunc); | |
public static bool operator ==(Option<T>? lhs, Option<T>? rhs) => lhs?.Equals(rhs) ?? rhs == null; | |
public static bool operator !=(Option<T>? lhs, Option<T>? rhs) => !(lhs == rhs); | |
public override bool Equals(object? other) => other is Option<T> opt ? Equals(opt) : false; | |
public bool Equals(Option<T>? other) => (this, other) switch | |
{ | |
(_, null) => false, | |
(Some<T>(var val1), Some<T>(var val2)) => object.Equals(val1, val2), | |
(None<T>(), None<T>()) => true, | |
_ => false, | |
}; | |
public override int GetHashCode() => this switch | |
{ | |
Some<T>(var value) => value?.GetHashCode() ?? 0, | |
_ => 0, | |
}; | |
} | |
public sealed class Some<T> : Option<T> | |
{ | |
public T Value { get; } | |
public override bool IsSome { get; } = true; | |
public override bool IsNone { get; } = false; | |
internal Some(T value) => Value = value; | |
public override Option<U> Select<U>(Func<T, U> f) => Option.Create(f(Value)); | |
public override Option<T> Where(Func<T, bool> f) => f(Value) ? this : None; | |
public override Option<U> SelectMany<U>(Func<T, Option<U>> f) => f(Value); | |
public override Option<V> SelectMany<U, V>(Func<T, Option<U>> f, Func<T, U, V> g) => | |
SelectMany(x => f(x).SelectMany(y => Option.Create(g(x, y)))); | |
public override T OrDefault(T _) => Value; | |
public override T OrDefault(Func<T> _) => Value; | |
public override string ToString() => $"Some({Value})"; | |
public void Deconstruct(out T value) => value = Value; | |
} | |
public sealed class None<T> : Option<T> | |
{ | |
public override bool IsSome { get; } = false; | |
public override bool IsNone { get; } = true; | |
internal None() { } | |
public override Option<U> Select<U>(Func<T, U> f) => new None<U>(); | |
public override Option<T> Where(Func<T, bool> f) => this; | |
public override Option<U> SelectMany<U>(Func<T, Option<U>> f) => new None<U>(); | |
public override Option<V> SelectMany<U, V>(Func<T, Option<U>> f, Func<T, U, V> g) => new None<V>(); | |
public override T OrDefault(T defaultValue) => defaultValue; | |
public override T OrDefault(Func<T> defaultFunc) => defaultFunc(); | |
public override string ToString() => "None"; | |
public void Deconstruct() { } | |
public static implicit operator None<T>(None<dynamic>? none) => new None<T>(); | |
public static implicit operator None<dynamic>(None<T>? none) => Option.None; | |
} |
This file contains 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
class Sample | |
{ | |
static void Main() | |
{ | |
var concatinated = | |
from x in Option.Create("Hello") | |
from y in Option.Create("World") | |
select $"{x}, {y}!"; | |
Console.WriteLine(concatinated.OrDefault("(failed)")); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment