Skip to content

Instantly share code, notes, and snippets.

@dimchansky
Last active August 29, 2015 14:17
Show Gist options
  • Save dimchansky/638222f352f294b88701 to your computer and use it in GitHub Desktop.
Save dimchansky/638222f352f294b88701 to your computer and use it in GitHub Desktop.
Maybe monad in C#
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