Last active
August 29, 2015 14:07
-
-
Save nkoneko/10c5ac97196d50232613 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 | |
{ | |
// 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))); | |
} | |
} | |
} |
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 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(); | |
} | |
} | |
} |
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 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