Last active
August 29, 2015 14:07
-
-
Save nkoneko/51dd049fa2cf4c2a8f7f 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
namespace System.Monad | |
{ | |
public class Error | |
{ | |
private Error() { } | |
public sealed class ErrorM<A> : Error, IMonad<A, Error> | |
{ | |
public IMonad<B, Error> Return<B>(B val) | |
{ | |
return new ErrorM<B> { Value = val, Exc = default(Exception), HasError = false }; | |
} | |
public IMonad<B, Error> Bind<B>(Func<A, IMonad<B, Error>> f) | |
{ | |
var exc = Exc; | |
return HasError | |
? new ErrorM<B> { Exc = exc, HasError = true } | |
: f(Value); | |
} | |
public A Value { get; internal set; } | |
public Exception Exc { get; internal set; } | |
public bool HasError { get; internal set; } | |
} | |
} | |
namespace Trans | |
{ | |
public class ErrorTrans<M> | |
{ | |
private ErrorTrans() { } | |
public sealed class ErrorT<A> : ErrorTrans<M>, IMonad<A, ErrorTrans<M>> | |
{ | |
public IMonad<B, ErrorTrans<M>> Return<B>(B val) | |
{ | |
var v = Value; | |
return new ErrorT<B> { Value = v.Return<Error.ErrorM<B>>(new Error.ErrorM<B> { Value = val }) }; | |
} | |
private IMonad<Error.ErrorM<B>, M> h<B>(Error.ErrorM<A> ma, Func<A, IMonad<B, ErrorTrans<M>>> f) | |
{ | |
var v = Value; | |
return ma.HasError | |
? v.Return<Error.ErrorM<B>>(new Error.ErrorM<B> { HasError = true, Exc = ma.Exc }) | |
: f(ma.Value).SafeCast<B, ErrorT<B>, ErrorTrans<M>>().Value; | |
} | |
public IMonad<B, ErrorTrans<M>> Bind<B>(Func<A, IMonad<B, ErrorTrans<M>>> f) | |
{ | |
var x = Value.Bind(y => h(y, f)); | |
return new ErrorT<B> { Value = x }; | |
} | |
public IMonad<Error.ErrorM<A>, M> Value { get; internal set; } | |
} | |
} | |
} | |
} |
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
namespace System.Monad | |
{ | |
// Monad m => m A | |
// e.g. Maybe Int when m = Maybe and A = Int | |
public interface IMonad<A, M> | |
{ | |
// Monad m => b -> m b | |
IMonad<B, M> Return<B>(B val); | |
// Monad m => m a -> (a -> m b) -> m b | |
IMonad<B, M> Bind<B>(Func<A, IMonad<B, M>> f); | |
} | |
public static class MonadHelper | |
{ | |
public static N SafeCast<A, N, M>(this IMonad<A, M> m) | |
where N : IMonad<A, M> | |
{ | |
return (N)m; | |
} | |
} | |
public static class MonadLinqAdapter | |
{ | |
public static IMonad<C, M> SelectMany<A, B, C, M> | |
( | |
this IMonad<A, M> ma, | |
Func<A, IMonad<B, M>> k, | |
Func<A, B, C> s | |
) | |
{ | |
// in C# in Haskell | |
return ma .Bind(x => // do x <- m | |
k(x).Bind(y => ma. // y <- k(x) | |
Return // return | |
(s(x, y)))); // s(x, y) | |
} | |
public static IMonad<B, M> Select<A, B, M> | |
( | |
this IMonad<A, M> ma, | |
Func<A, IMonad<B, M>> s | |
) | |
{ | |
// in C# in Haskell | |
return ma.Bind(x => // do x <- ma | |
s(x)); // s(x) | |
} | |
} | |
} |
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
namespace System.Monad | |
{ | |
public class Option | |
{ | |
private Option() { } | |
public sealed class OptionM<A> : Option, IMonad<A, Option> | |
{ | |
public IMonad<B, Option> Return<B>(B val) | |
{ | |
return OptionM<B>.Some(val); | |
} | |
public IMonad<B, Option> Bind<B>(Func<A, IMonad<B, Option>> f) | |
{ | |
return HasValue ? f(Value) : OptionM<B>.None; | |
} | |
public static OptionM<T> Some<T>(T val) | |
{ | |
return new OptionM<T> { Value = val, HasValue = true }; | |
} | |
public static OptionM<A> None = new OptionM<A>{ HasValue = false }; | |
public A Value { get; private set; } | |
public bool HasValue { get; private set; } | |
} | |
} | |
namespace Trans | |
{ | |
public class OptionTrans<M> | |
{ | |
private OptionTrans() {} | |
public sealed class OptionT<A> : OptionTrans<M>, IMonad<A, OptionTrans<M>> | |
{ | |
public IMonad<B, OptionTrans<M>> Return<B>(B val) | |
{ | |
var v = Value; | |
return new OptionT<B>{ | |
Value = v.Return( | |
Option.OptionM<B>.Some(val)) | |
}; | |
} | |
private IMonad<Option.OptionM<B>, M> h<B>(Option.OptionM<A> x, | |
Func<A, IMonad<B, OptionTrans<M>>> f) | |
{ | |
return x.HasValue | |
? f(x.Value).SafeCast<B, OptionT<B>, OptionTrans<M>>().Value | |
: Value.Return<Option.OptionM<B>>(Option.OptionM<B>.None); | |
} | |
public IMonad<B, OptionTrans<M>> Bind<B>(Func<A, IMonad<B, OptionTrans<M>>> f) | |
{ | |
var x = Value.Bind(y => h(y, f)); | |
return new OptionT<B> { Value = x }; | |
} | |
public IMonad<Option.OptionM<A>, M> Value { get; internal set; } | |
} | |
} | |
} | |
public static class OptionMonadHelper | |
{ | |
public static Func<Option.OptionM<B>> Lift<B>(this Func<B> f) | |
{ | |
return () => | |
{ | |
var x = f(); | |
return x == null ? Option.OptionM<B>.None : Option.OptionM<B>.Some(x); | |
}; | |
} | |
public static Func<Trans.OptionTrans<M>.OptionT<B>> LiftT<B, M>(this Func<IMonad<B, M>> f) | |
{ | |
Func<IMonad<Option.OptionM<B>, M>> g = () => | |
{ | |
var x = f(); | |
return x.Bind(y => x.Return(Option.OptionM<B>.Some(y))); | |
}; | |
return () => | |
{ | |
var m = g(); | |
return new Trans.OptionTrans<M>.OptionT<B> { Value = m }; | |
}; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment