Last active
August 29, 2015 14:17
-
-
Save dimchansky/638222f352f294b88701 to your computer and use it in GitHub Desktop.
Maybe monad 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; | |
namespace MaybeMonad | |
{ | |
internal class Program | |
{ | |
private static void Main() | |
{ | |
var result = from a in "Hello ".ToMaybe() | |
from b in Nothing<string>.Instance | |
from c in "World!".ToMaybe() | |
from d in " :)".ToMaybe() | |
select a + b + c + d; | |
/* | |
var result = "Hello ".ToMaybe() | |
.SelectMany(a => Nothing<string>.Instance, (a, b) => new {a, b}) | |
.SelectMany(@t => "World!".ToMaybe(), (@t, c) => new {@t, c}) | |
.SelectMany(@t => " :)".ToMaybe(), (@t, d) => @t.@t.a + @t.@t.b + @t.c + d); | |
*/ | |
Console.WriteLine("Result: " + result); | |
Console.WriteLine(); | |
/* | |
ctor Just<String> | |
Bind on Just | |
ctor Nothing<String> | |
Bind on Nothing | |
ctor Nothing<<>f__AnonymousType0`2> | |
Bind on Nothing | |
ctor Nothing<<>f__AnonymousType1`2> | |
Bind on Nothing | |
Result: Nothing | |
*/ | |
var result2 = | |
"Hello ".ToMaybe().SelectMany(a => | |
Nothing<string>.Instance.SelectMany(b => | |
"World!".ToMaybe().SelectMany(c => | |
" :)".ToMaybe().Map(d => a + b + c + d)))); | |
Console.WriteLine("Result2: " + result2); | |
/* | |
ctor Just<String> | |
Bind on Just | |
Bind on Nothing | |
Result2: Nothing | |
*/ | |
} | |
} | |
public interface IMaybe<T> | |
{ | |
IMaybe<TR> Bind<TR>(Func<T, IMaybe<TR>> selector); | |
} | |
public sealed class Nothing<T> : IMaybe<T> | |
{ | |
public static readonly Nothing<T> Instance = new Nothing<T>(); | |
private Nothing() | |
{ | |
Console.WriteLine("ctor Nothing<" + typeof (T).Name + ">"); | |
} | |
public IMaybe<TR> Bind<TR>(Func<T, IMaybe<TR>> selector) | |
{ | |
Console.WriteLine("Bind on Nothing"); | |
return Nothing<TR>.Instance; | |
} | |
public override string ToString() | |
{ | |
return "Nothing"; | |
} | |
} | |
public sealed class Just<T> : IMaybe<T> | |
{ | |
private readonly T _value; | |
public T Value | |
{ | |
get { return _value; } | |
} | |
public Just(T value) | |
{ | |
Console.WriteLine("ctor Just<" + typeof (T).Name + ">"); | |
_value = value; | |
} | |
public IMaybe<TR> Bind<TR>(Func<T, IMaybe<TR>> selector) | |
{ | |
Console.WriteLine("Bind on Just"); | |
return selector(Value); | |
} | |
public override string ToString() | |
{ | |
return "Just(" + Value + ")"; | |
} | |
} | |
internal static class Ext | |
{ | |
public static IMaybe<T> ToMaybe<T>(this T value) | |
{ | |
return new Just<T>(value); | |
} | |
public static IMaybe<TB> SelectMany<TA, TB>( | |
this IMaybe<TA> a, | |
Func<TA, IMaybe<TB>> selector) | |
{ | |
return a.Bind(selector); | |
} | |
public static IMaybe<TR> SelectMany<TA, TB, TR>( | |
this IMaybe<TA> a, | |
Func<TA, IMaybe<TB>> selector, | |
Func<TA, TB, TR> resultSelector) | |
{ | |
return a.Bind(v => selector(v).Bind(b => resultSelector(v, b).ToMaybe())); | |
} | |
public static IMaybe<TB> Map<TA, TB>( | |
this IMaybe<TA> a, | |
Func<TA, TB> selector) | |
{ | |
return a.Bind(v => selector(v).ToMaybe()); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment