Skip to content

Instantly share code, notes, and snippets.

@nkoneko
Last active August 29, 2015 14:07
Show Gist options
  • Save nkoneko/51dd049fa2cf4c2a8f7f to your computer and use it in GitHub Desktop.
Save nkoneko/51dd049fa2cf4c2a8f7f to your computer and use it in GitHub Desktop.
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; }
}
}
}
}
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)
}
}
}
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