Created
December 11, 2012 11:19
-
-
Save bradphelan/4257876 to your computer and use it in GitHub Desktop.
Maybe<T> Implementation 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; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Reactive.Linq; | |
namespace FunctionalExtensions | |
{ | |
#region Maybe | |
public delegate Maybe<TOutput> Converter<in TInput, out TOutput>(TInput input); | |
public delegate TOutput ElseDelegate<out TOutput>(); | |
public delegate Maybe<TOutput> ElseDelegate2<out TOutput>(); | |
public interface Maybe<out TResult> : IEnumerable <TResult> | |
{ | |
Maybe<B> Bind<B>(Converter<TResult, B> f); | |
TResult Value(); | |
bool IsSome(); | |
} | |
public static class Maybe | |
{ | |
public static Maybe<T> None<T>(){ | |
return new NoneImpl<T>(); | |
} | |
} | |
public interface None<out TResult> : Maybe<TResult> | |
{ | |
} | |
public interface Some<out TResult> : Maybe<TResult> | |
{ | |
} | |
public static class MaybeMixins | |
{ | |
public static IEnumerable<T> WhereIsSome<T>(this IEnumerable<Maybe<T>> This){ | |
return This.SelectMany(x => x, (x,y)=>y); | |
} | |
public static IObservable<T> WhereIsSome<T>(this IObservable<Maybe<T>> This){ | |
return This.SelectMany(x => x, (x,y)=>y); | |
} | |
public static T Else<T>(this Maybe<T> This, T defaultValue){ | |
if (This.IsSome()) | |
{ | |
return This.Value(); | |
} | |
else | |
{ | |
return defaultValue; | |
} | |
} | |
public static T Else<T>(this Maybe<T> This, ElseDelegate<T> del){ | |
if (This.IsSome()) | |
{ | |
return This.Value(); | |
} | |
else | |
{ | |
return del(); | |
} | |
} | |
public static Maybe<T> Else<T>(this Maybe<T> This, ElseDelegate2<T> del){ | |
if (This.IsSome()) | |
{ | |
return This; | |
} | |
else | |
{ | |
return del(); | |
} | |
} | |
public static T Else<TException, T>(this Maybe<T> This) | |
where TException : Exception, new() | |
{ | |
if (This.IsSome()) | |
{ | |
return This.Value(); | |
} | |
else | |
{ | |
throw new TException(); | |
} | |
} | |
public static Maybe<TResult> Select<TSource, TResult>(this Maybe<TSource> m, Func<TSource, TResult> f) | |
{ | |
return m.Bind(x => f(x).ToMaybe()); | |
} | |
public static Maybe<TResult> SelectMany<TSource, TResult>(this Maybe<TSource> m, Func<TSource, Maybe<TResult>> f) | |
{ | |
return m.Bind(x => f(x)); | |
} | |
public static Maybe<TResult> SelectMany<TSource, TMaybe, TResult>(this Maybe<TSource> m, Func<TSource, Maybe<TMaybe>> f, Func<TSource, TMaybe, TResult> g) | |
{ | |
return m.Bind(x => f(x).Bind(y => g(x, y).ToMaybe())); | |
} | |
public static Maybe<T> Where<T>(this Maybe<T> This, Predicate<T> p){ | |
return This.Bind((x) => (p(x) ? x.ToMaybe() : Maybe.None<T>())); | |
} | |
public static Maybe<TSource> ToMaybe<TSource>(this TSource This) | |
{ | |
if (This == null) | |
{ | |
return new NoneImpl<TSource>(); | |
} | |
else | |
{ | |
return new SomeImpl<TSource>(This); | |
} | |
} | |
} | |
internal class NoneImpl<TResult> : None<TResult>{ | |
public NoneImpl() | |
{} | |
public IEnumerator<TResult> GetEnumerator() | |
{ yield break; } | |
IEnumerator IEnumerable.GetEnumerator() | |
{ yield break; } | |
public virtual bool IsSome() { return false; } | |
public Maybe<TOutput> Bind<TOutput>(Converter<TResult, TOutput> f) | |
{ | |
return new NoneImpl<TOutput>(); | |
} | |
public virtual TResult Value() | |
{ | |
throw new IndexOutOfRangeException("None has no value"); | |
} | |
} | |
internal class SomeImpl<TResult> : Some<TResult> | |
{ | |
private TResult _Value; | |
public SomeImpl(TResult value) | |
{ | |
_Value = value; | |
} | |
public IEnumerator<TResult> GetEnumerator() | |
{ yield return _Value; } | |
IEnumerator IEnumerable.GetEnumerator() | |
{ yield return _Value; } | |
public virtual bool IsSome() { return true; } | |
public Maybe<TOutput> Bind<TOutput>(Converter<TResult, TOutput> f) | |
{ | |
return f(_Value); | |
} | |
public virtual TResult Value() | |
{ | |
return this._Value; | |
} | |
} | |
#endregion | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment