Skip to content

Instantly share code, notes, and snippets.

@ntreu14
Created August 29, 2019 14:19
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ntreu14/72e56ea8273df854cca8fad7502f7b60 to your computer and use it in GitHub Desktop.
Save ntreu14/72e56ea8273df854cca8fad7502f7b60 to your computer and use it in GitHub Desktop.
Implementation of an option in C#
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