Created
August 29, 2019 14:19
-
-
Save ntreu14/72e56ea8273df854cca8fad7502f7b60 to your computer and use it in GitHub Desktop.
Implementation of an option in C#
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
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
namespace OptionExample | |
{ | |
public interface IOption<T> | |
{ | |
bool IsSome { get; } | |
bool IsSomeOf(T value); | |
bool IsNone { get; } | |
TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> onNone); | |
IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f); | |
IOption<TResult> Map<TResult>(Func<T, TResult> f); | |
T Or(T aDefault); | |
void Iter(Action<T> onSome); | |
IList<T> ToList(); | |
} | |
public static class Some | |
{ | |
public static IOption<T> Of<T>(T value) => Some<T>.Of(value); | |
} | |
public static class Option | |
{ | |
public static IOption<T> FromNullable<T>(T? v) where T : struct => | |
v.HasValue ? Some<T>.Of(v.Value) : new None<T>(); | |
public static IOption<T> FromMaybeNull<T>(T v) where T : class => | |
v != null ? Some<T>.Of(v) : new None<T>(); | |
public static IEnumerable<T> ToEnumerable<T>(IOption<T> value) => | |
value.Match(v => new[] { v }, Enumerable.Empty<T>); | |
public static IEnumerable<T> Concat<T>(IEnumerable<IOption<T>> values) => | |
values.SelectMany(ToEnumerable); | |
public static IOption<TElem> TryFind<TElem>(IEnumerable<TElem> values, Func<TElem, bool> predicate) => | |
values.Any(predicate) ? Some<TElem>.Of(values.First(predicate)) : new None<TElem>(); | |
public static IOption<TElem> TryFirst<TElem>(IEnumerable<TElem> values) => | |
values.Any() ? Some<TElem>.Of(values.First()) : new None<TElem>(); | |
public static IOption<TElem> TryKey<TKey, TElem>(TKey key, IDictionary<TKey, TElem> dict) => | |
dict.ContainsKey(key) ? Some<TElem>.Of(dict[key]) : new None<TElem>(); | |
public static IOption<TResult> FromOneOrManyOrNone<TElem, TResult>(IEnumerable<TElem> values, Func<TElem, TResult> whenOne, Func<IEnumerable<TElem>, TResult> whenMany) | |
{ | |
switch (values.Count()) | |
{ | |
case 1: | |
return Some<TResult>.Of(whenOne(values.First())); | |
case 0: | |
return new None<TResult>(); | |
default: | |
return Some<TResult>.Of(whenMany(values)); | |
} | |
} | |
} | |
public class Some<T> : IOption<T> | |
{ | |
protected bool Equals(Some<T> other) => | |
System.Collections.Generic.EqualityComparer<T>.Default.Equals(Value, other.Value); | |
public override bool Equals(object obj) | |
{ | |
if (ReferenceEquals(null, obj)) return false; | |
if (ReferenceEquals(this, obj)) return true; | |
if (obj.GetType() != this.GetType()) return false; | |
return Equals((Some<T>)obj); | |
} | |
public override int GetHashCode() => | |
System.Collections.Generic.EqualityComparer<T>.Default.GetHashCode(Value); | |
public T Value { get; } | |
private Some(T value) | |
{ | |
Value = value; | |
} | |
public static IOption<T> Of(T value) => new Some<T>(value); | |
public bool IsSome => true; | |
public bool IsSomeOf(T value) => Value.Equals(value); | |
public bool IsNone => false; | |
public TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> _) => onSome(Value); | |
public IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f) => f(Value); | |
public IOption<TResult> Map<TResult>(Func<T, TResult> f) => new Some<TResult>(f(Value)); | |
public T Or(T _) => Value; | |
public void Iter(Action<T> onSome) => onSome(Value); | |
public IList<T> ToList() => new List<T> { Value }; | |
} | |
public class None<T> : IOption<T> | |
{ | |
protected bool Equals(None<T> other) => true; | |
public override bool Equals(object obj) | |
{ | |
if (ReferenceEquals(null, obj)) return false; | |
if (ReferenceEquals(this, obj)) return true; | |
if (obj.GetType() != this.GetType()) return false; | |
return Equals((None<T>)obj); | |
} | |
public override int GetHashCode() => 0; | |
public bool IsSome => false; | |
public bool IsSomeOf(T value) => false; | |
public bool IsNone => true; | |
public TResult Match<TResult>(Func<T, TResult> _, Func<TResult> onNone) => onNone(); | |
public IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> _) => new None<TResult>(); | |
public IOption<TResult> Map<TResult>(Func<T, TResult> _) => new None<TResult>(); | |
public T Or(T aDefault) => aDefault; | |
public void Iter(Action<T> _) { } | |
public IList<T> ToList() => new List<T>(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment