Skip to content

Instantly share code, notes, and snippets.

@matarillo
Last active December 19, 2015 23:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matarillo/166e02f82fc49eec4052 to your computer and use it in GitHub Desktop.
Save matarillo/166e02f82fc49eec4052 to your computer and use it in GitHub Desktop.
using System;
class Program
{
private static void Main(string[] args)
{
var m1 = 1.ToMaybe();
var m2 = 2.ToMaybe();
var m3 = (from v1 in m1
from v2 in m2
select v1 + v2).AsMaybe();
if (m3.HasValue)
{
Console.WriteLine(m3.Value);
}
else
{
Console.WriteLine("Nothing");
}
}
}
public abstract class Functor<TImpl>
where TImpl : Functor<TImpl>
{
public abstract Value<TImpl, TResult> Map<T, TResult>(Value<TImpl, T> m, Func<T, TResult> f);
}
public abstract class Value<TImpl, T>
where TImpl : Functor<TImpl>
{
public abstract TImpl TypeClass { get; }
}
public abstract class Applicative<TImpl> : Functor<TImpl>
where TImpl : Applicative<TImpl>
{
public abstract Value<TImpl, T> Pure<T>(T value);
public abstract Value<TImpl, TResult> Ap<T, TResult>(Value<TImpl, T> m, Value<TImpl, Func<T, TResult>> mf);
public override Value<TImpl, TResult> Map<T, TResult>(Value<TImpl, T> m, Func<T, TResult> f)
{
return Ap(m, Pure(f));
}
}
public abstract class Monad<TImpl> : Applicative<TImpl> where TImpl : Monad<TImpl>
{
public abstract Value<TImpl, T> Unit<T>(T value);
public abstract Value<TImpl, TResult> Bind<T, TResult>(Value<TImpl, T> m, Func<T, Value<TImpl, TResult>> f);
public override Value<TImpl, T> Pure<T>(T value)
{
return Unit(value);
}
public override Value<TImpl, TResult> Ap<T, TResult>(Value<TImpl, T> m, Value<TImpl, Func<T, TResult>> mf)
{
return Bind(m, x => Bind(mf, f => Unit(f(x))));
}
}
public static class MonadEx
{
public static Value<TImpl, TResult> SelectMany<TImpl, TSource, TCollection, TResult>(
this Value<TImpl, TSource> source,
Func<TSource, Value<TImpl, TCollection>> selector,
Func<TSource, TCollection, TResult> resultSelector)
where TImpl : Monad<TImpl>
{
return
source.TypeClass.Bind(source, x =>
source.TypeClass.Bind(selector(x), c =>
source.TypeClass.Unit(resultSelector(x, c))));
}
}
public class Maybe : Monad<Maybe>
{
public static readonly Maybe Instance = new Maybe();
public override Value<Maybe, TValue> Unit<TValue>(TValue value)
{
return new Maybe<TValue>(value);
}
public override Value<Maybe, TResult> Bind<TValue, TResult>(Value<Maybe, TValue> m,
Func<TValue, Value<Maybe, TResult>> f)
{
var mm = (Maybe<TValue>)m;
return (mm.HasValue) ? f(mm.Value) : Maybe<TResult>.Nothing;
}
}
public class Maybe<T> : Value<Maybe, T>
{
public static readonly Maybe<T> Nothing = new Maybe<T>(false, default(T));
public override Maybe TypeClass
{
get { return Maybe.Instance; }
}
private readonly bool _hasValue;
private readonly T _value;
private Maybe(bool hasValue, T value)
{
_hasValue = hasValue;
_value = value;
}
public Maybe(T value)
: this(true, value)
{
}
public bool HasValue
{
get { return _hasValue; }
}
public T Value
{
get
{
if (!_hasValue) throw new InvalidOperationException();
return _value;
}
}
}
public static class MaybeEx
{
public static Maybe<T> ToMaybe<T>(this T value)
{
return new Maybe<T>(value);
}
public static Maybe<T> AsMaybe<T>(this Value<Maybe, T> m)
{
return (Maybe<T>)m;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment