Skip to content

Instantly share code, notes, and snippets.

@bradphelan
Created December 11, 2012 11: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 bradphelan/4257876 to your computer and use it in GitHub Desktop.
Save bradphelan/4257876 to your computer and use it in GitHub Desktop.
Maybe<T> Implementation in C#
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