Last active
December 19, 2015 23:24
-
-
Save matarillo/166e02f82fc49eec4052 to your computer and use it in GitHub Desktop.
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; | |
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