Skip to content

Instantly share code, notes, and snippets.

@afifmohammed
Forked from hodzanassredin/AsyncMonad.cs
Created February 13, 2017 01:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save afifmohammed/283c0821ce454698ebaa2769e2bd69f2 to your computer and use it in GitHub Desktop.
Save afifmohammed/283c0821ce454698ebaa2769e2bd69f2 to your computer and use it in GitHub Desktop.
tutorial2 finished monad transformer
using System;
using System.Threading.Tasks;
namespace GenericMonad
{
public class Async
{
Async ()
{
}
public class AsyncM<T>: Async, IMonad<T, Async>
{
#region IMonad implementation
public IMonad<TB, Async> Return<TB> (TB val)
{
return new AsyncM<TB> (Task<TB>.FromResult (val));
}
//helper method two tasks composition
private static async Task<TB> BindTasks<TB> (Task<T> m, Func<T, Task<TB>> f)
{
var r = await m;
return await f (r);
}
public IMonad<TB, Async> Bind<TB> (Func<T, IMonad<TB, Async>> f)
{
return new AsyncM<TB> (BindTasks (this.Task, (t) => f (t).CastM<TB, AsyncM<TB>, Async> ().Task));
}
#endregion
public AsyncM (Task<T> val)
{
Task = val;
}
public Task<T> Task {
get;
set;
}
}
}
public static class AsyncMonad
{
public static Func<Async.AsyncM<TB>> Lift<TB> (this Func<Task<TB>> f)
where TB : class
{
return () => {
var res = f ();
return new Async.AsyncM<TB> (res);
};
}
}
}
using System;
namespace GenericMonad
{
public class CheckedVal<T>
{
CheckedVal (T val)
{
Value = val;
}
public static CheckedVal<T> Success (T val)
{
return new CheckedVal<T> (val){ IsFailed = false };
}
public static CheckedVal<T> Fail ()
{
return new CheckedVal<T> (default(T)){ IsFailed = true };
}
public static CheckedVal<T> ToCheck (T val)
{
return val == null ? Fail () : Success (val);
}
public bool IsFailed {
get;
private set;
}
public T Value {
get;
private set;
}
public override string ToString ()
{
return string.Format ("[Check: IsFailed={0}, Value={1}]", IsFailed, Value);
}
}
}
using System;
namespace GenericMonad
{
public class Check
{
Check ()
{
}
public class CheckM<T>: Check, IMonad<T, Check>
{
#region IMonad implementation
public IMonad<TB, Check> Return<TB> (TB val)
{
return CheckM<TB>.Success (val);
}
public IMonad<TB, Check> Bind<TB> (Func<T, IMonad<TB, Check>> f)
{
return this.Value.IsFailed ? CheckM<TB>.Fail () : f (this.Value.Value);
}
#endregion
public CheckM (CheckedVal<T> val)
{
Value = val;
}
public static CheckM<T> Success (T val)
{
return new CheckM<T> (CheckedVal<T>.Success (val));
}
public static CheckM<T> Fail ()
{
return new CheckM<T> (CheckedVal<T>.Fail ());
}
public CheckedVal<T> Value {
get;
private set;
}
public override string ToString ()
{
return Value.ToString ();
}
}
}
}
using System;
namespace GenericMonad
{
public class CheckForT<TMI>
{
CheckForT ()
{
}
public class CheckT<T>: CheckForT<TMI>, IMonad<T, CheckForT<TMI>>
{
#region IMonad implementation
public IMonad<TB, CheckForT<TMI>> Return<TB> (TB val)
{
return new CheckT<TB> (Value.Return<CheckedVal<TB>> (CheckedVal<TB>.Success (val)));
}
private IMonad<CheckedVal<TB>,TMI> BindInternal<TB> (CheckedVal<T> check,
Func<T, IMonad<TB, CheckForT<TMI>>> f)
{
return check.IsFailed
? Value.Return<CheckedVal<TB>> (CheckedVal<TB>.Fail ())
: f (check.Value).CastM<TB, CheckT<TB>,CheckForT<TMI>> ().Value;
}
public IMonad<TB, CheckForT<TMI>> Bind<TB> (Func<T, IMonad<TB, CheckForT<TMI>>> f)
{
var tmp = Value.Bind<CheckedVal<TB>> (check => BindInternal (check, f));
return new CheckT<TB> (tmp);
}
#endregion
public CheckT (IMonad<CheckedVal<T>,TMI> val)
{
Value = val;
}
public IMonad<CheckedVal<T>,TMI> Value {
get;
private set;
}
}
}
public static class CheckMonad
{
public static Func<Check.CheckM<TB>> Lift<TB> (this Func<TB> f)
where TB : class
{
return () => {
var res = f ();
return new Check.CheckM<TB> (CheckedVal<TB>.ToCheck (res));
};
}
public static Func<Check.CheckM<TB>> Lift<TB> (this Func<CheckedVal<TB>> f)
where TB : class
{
return () => {
var res = f ();
return new Check.CheckM<TB> (res);
};
}
public static Func<CheckForT<TMI>.CheckT<TB>> LiftT<TB,TMI> (this Func<IMonad<TB,TMI>> f)
where TB : class
{
Func<IMonad<CheckedVal<TB>,TMI>> checkF = () => {
var m = f ();
return m.Bind (val => m.Return (CheckedVal<TB>.ToCheck (val)));
};
return () => {
var monad = checkF ();
return new CheckForT<TMI>.CheckT<TB> (monad);
};
}
}
}
using System;
namespace GenericMonad
{
public interface IMonad<T, TMI>
{
IMonad<TB,TMI> Return<TB> (TB val);
IMonad<TB,TMI> Bind<TB> (Func<T, IMonad<TB,TMI>> f);
}
public static class MonadSyntax
{
public static TM CastM<T, TM, TMB> (this IMonad<T, TMB> m)
where TM : IMonad<T, TMB>
{
return (TM)m;//safe for single inheritance
}
public static IMonad<V, TMI> SelectMany<T, TMI, U, V>
(
this IMonad<T, TMI> id,
Func<T, IMonad<U, TMI>> k,
Func<T, U, V> s)
{
return id.Bind (x => k (x).Bind (y => id.Return (s (x, y))));
}
public static IMonad<B, TMI> Select<A, B, TMI> (this IMonad<A, TMI> a, Func<A, IMonad<B, TMI>> select)
{
return a.Bind (aval => select (aval));
}
}
}
using System;
using System.Net;
using System.Threading.Tasks;
namespace GenericMonad
{
class MainClass
{
public static Task<String> GetData ()
{
//return Task<String>.FromResult ((string)null);
return new WebClient ().DownloadStringTaskAsync (new Uri ("http://google.com"));
}
static void Main (string[] args)
{
//expected Check<Test> but Check<Check<Test>>
var getData = CheckMonad.LiftT (AsyncMonad.Lift (GetData));
var res =
from a in getData ()
from b in getData ()
select a.Substring (0, 10) + b.Substring (10, 20);
var checkT = res.CastM<string, CheckForT<Async>.CheckT<string>, CheckForT<Async> > ();
var task = checkT.Value.CastM<CheckedVal<string>, Async.AsyncM<CheckedVal<string>>, Async> ().Task;
Console.WriteLine (task.Result);
Console.WriteLine ("finished!");
Console.ReadLine ();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment