Skip to content

Instantly share code, notes, and snippets.

@nkoneko
Last active August 29, 2015 14:07
Show Gist options
  • Save nkoneko/10c5ac97196d50232613 to your computer and use it in GitHub Desktop.
Save nkoneko/10c5ac97196d50232613 to your computer and use it in GitHub Desktop.
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)
}
public static IMonad<B, M> Select<A, B, M>(this IMonad<A, M> ma, Func<A, B> f)
{
return ma.Bind(a => ma.Return<B>(f(a)));
}
}
}
namespace MainModule
{
class Program
{
// http://www.geocities.jp/m_hiroi/func/haskell18.html
// の例をpure C#でやってみる。
static IMonad<int, Reader<int>> Add10()
{
// do x <- ask
// return $ x + 10
return from x in Reader<int>.Ask<int>()
select x + 10;
}
static void Main(string[] args)
{
// do x <- add10
// y <- local (+100) add10
// z <- ask
// return (x, y, z)
var test = from x in Add10()
from y in Reader<int>.Local<int, int>(n => n + 100, Add10())
from z in Reader<int>.Ask<int>()
select new Tuple<int, int, int>(x, y, z);
// let v = runReader test 100
var v = test.RunReader(100);
Console.WriteLine(v);
Console.ReadLine();
}
}
}
namespace System.Monad
{
public class Reader<Env>
{
private Reader() { }
public sealed class ReaderM<A> : Reader<Env>, IMonad<A, Reader<Env>>
{
#region IMonad implementation
public IMonad<B, Reader<Env>> Return<B>(B val)
{
return new Reader<Env>.ReaderM<B> { Value = env => val };
}
public IMonad<B, Reader<Env>> Bind<B>(Func<A, IMonad<B, Reader<Env>>> f)
{
var r = Value;
return new Reader<Env>.ReaderM<B>
{
Value = env =>
{
var s = f(r(env));
return s.SafeCast<B, Reader<Env>.ReaderM<B>, Reader<Env>>().Value(env);
}
};
}
#endregion
public Func<Env, A> Value { get; internal set; }
}
public static IMonad<E, Reader<E>> Ask<E>()
{
return new Reader<E>.ReaderM<E> { Value = x => x };
}
public static IMonad<A, Reader<E>> Local<E, A>(Func<E, E> f, IMonad<A, Reader<E>> ma)
{
return new Reader<E>.ReaderM<A>
{
Value = env =>
{
var r = ma.SafeCast<A, Reader<E>.ReaderM<A>, Reader<E>>().Value;
return r(f(env));
}
};
}
public static IMonad<A, Reader<E>> Asks<E, A>(Func<E, A> f)
{
var me = Ask<E>();
return me.Bind(env => me.Return(f(env)));
}
}
public static class ReaderMonadEx
{
public static Func<Env, A> RunReader<Env, A>(this IMonad<A, Reader<Env>> ma)
{
return ma.SafeCast<A, Reader<Env>.ReaderM<A>, Reader<Env>>().Value;
}
public static Func<Env, IMonad<A, M>> RunReader<Env, A, M>(this IMonad<A, Trans.ReaderTrans<Env, M>> ma)
{
return ma.SafeCast<A, Trans.ReaderTrans<Env, M>.ReaderT<A>, Trans.ReaderTrans<Env, M>>().Value;
}
public static A RunReader<Env, A>(this IMonad<A, Reader<Env>> ma, Env env)
{
return ma.RunReader()(env);
}
}
namespace Trans
{
public class ReaderTrans<Env, M>
{
private ReaderTrans() { }
public sealed class ReaderT<A> : ReaderTrans<Env, M>, IMonad<A, ReaderTrans<Env, M>>
{
public IMonad<B, ReaderTrans<Env, M>> Return<B>(B val)
{
var rr = Value;
return new ReaderTrans<Env, M>.ReaderT<B>
{
Value = env => rr(env).Return<B>(val)
};
}
public IMonad<B, ReaderTrans<Env, M>> Bind<B>(Func<A, IMonad<B, ReaderTrans<Env, M>>> f)
{
var rr = Value;
return new ReaderTrans<Env, M>.ReaderT<B>
{
Value = env => rr(env).Bind(a => f(a).RunReader()(env))
};
}
public Func<Env, IMonad<A, M>> Value { get; internal set; }
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment