Last active
          September 19, 2017 17:27 
        
      - 
      
- 
        Save hodzanassredin/662b06daabb4f241d2f3 to your computer and use it in GitHub Desktop. 
    monad tutorial
  
        
  
    
      This file contains hidden or 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
    
  
  
    
  | using System; | |
| using System.Threading.Tasks; | |
| using System.Net; | |
| 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 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); | |
| }; | |
| } | |
| } | |
| class MainClass | |
| { | |
| public static Task<String> GetData () | |
| { | |
| return new WebClient().DownloadStringTaskAsync(new Uri("http://google.com")); | |
| } | |
| static void Main (string[] args) | |
| { | |
| //expected Check<Test> but Check<Check<Test>> | |
| var getData = AsyncMonad.Lift (GetData); | |
| var res = | |
| from a in getData () | |
| from b in getData () | |
| select a.Substring(0,10) + b.Substring(10,20); | |
| var task = res.CastM<string, Async.AsyncM<string>, Async> ().Task; | |
| Console.WriteLine (task.Result); | |
| Console.WriteLine ("finished!"); | |
| Console.ReadLine (); | |
| } | |
| } | |
| } | 
  
    
      This file contains hidden or 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
    
  
  
    
  | using System; | |
| namespace HigherKind | |
| { | |
| // interface IFunctor<T<_>> { | |
| // T<B> FMap<A, B>(Func<A, B> f, T<A> a); | |
| // } | |
| public interface IGeneric<T, TCONTAINER> | |
| { | |
| } | |
| public static class GenericExts | |
| { | |
| public static TM UpCast<T, TM, TMB> (this IGeneric<T, TMB> m) | |
| where TM : IGeneric<T, TMB> | |
| { | |
| return (TM)m;//safe for single inheritance | |
| } | |
| public static IGeneric<T, TMB> DownCast<T, TM, TMB> (this TM m) | |
| where TM : IGeneric<T, TMB> | |
| { | |
| return (TM)m;//safe for single inheritance | |
| } | |
| } | |
| public interface IFunctor<T> | |
| { | |
| CB FMap<A, B, CA, CB> (Func<A, B> f, CA a) | |
| where CA : IGeneric<A, T> | |
| where CB : IGeneric<B, T>; | |
| } | |
| public interface IFunctorSelf<TGENERIC, TSELF, TVALUE> | |
| where TSELF : IGeneric<TVALUE, TGENERIC> | |
| { | |
| CB FMap<B, CB> (Func<TVALUE, B> f) | |
| where CB : IGeneric<B, TGENERIC>; | |
| } | |
| public abstract class Wrapper | |
| { | |
| private Wrapper () | |
| { | |
| } | |
| public class WrapperImpl<T> : Wrapper, IGeneric<T, Wrapper>, IFunctorSelf<Wrapper, WrapperImpl<T> , T> | |
| { | |
| #region IFunctorSelf implementation | |
| public CB FMap<B, CB> (Func<T, B> f) where CB : IGeneric<B, Wrapper> | |
| { | |
| var res = new WrapperImpl<B> (f (Value)); | |
| return res.Cast<B, CB,Wrapper> (); | |
| } | |
| #endregion | |
| public WrapperImpl (T val) | |
| { | |
| Value = val; | |
| } | |
| public T Value { | |
| get; | |
| set; | |
| } | |
| } | |
| } | |
| class MainClass | |
| { | |
| public static void Main (string[] args) | |
| { | |
| var a = new Wrapper.WrapperImpl<int> (1); | |
| var b = a.FMap<int, Wrapper.WrapperImpl<int>> (x => -x); | |
| Console.WriteLine ("Value is: " + b.Value); | |
| Console.ReadLine (); | |
| } | |
| } | |
| } | 
  
    
      This file contains hidden or 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
    
  
  
    
  | using System; | |
| namespace MonadTutorial | |
| { | |
| public class Check<T> | |
| { | |
| private Check (T val) | |
| { | |
| Value = val; | |
| } | |
| public static Check<T> Success (T val) | |
| { | |
| return new Check<T> (val){ IsFailed = false }; | |
| } | |
| public static Check<T> Fail () | |
| { | |
| return new Check<T> (default(T)){ IsFailed = true }; | |
| } | |
| 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); | |
| } | |
| } | |
| public static class CheckMonad | |
| { | |
| public static Check<T> Return<T> (this T value) | |
| { | |
| return Check<T>.Success (value); | |
| } | |
| public static Check<U> Bind<T, U> (this Check<T> m, Func<T, Check<U>> k) //bind | |
| { | |
| return m.IsFailed ? Check<U>.Fail () : k (m.Value); | |
| } | |
| public static Func<Check<T>> Lift<T> (Func<T> f) | |
| where T : class | |
| { | |
| return () => { | |
| var res = f (); | |
| return res == null ? Check<T>.Fail () : Check<T>.Success (res); | |
| }; | |
| } | |
| public static Check<V> SelectMany<T, U, V> ( | |
| this Check<T> id, | |
| Func<T, Check<U>> k, | |
| Func<T, U, V> s) | |
| { | |
| return id.Bind (x => k (x).Bind (y => s (x, y).Return ())); | |
| } | |
| } | |
| class Test | |
| { | |
| public Test () | |
| { | |
| } | |
| } | |
| class MainClass | |
| { | |
| public static bool Bool () | |
| { | |
| return new Random ().Next () % 2 == 0 ? true : false; | |
| } | |
| public static T GetData<T> () | |
| where T : class, new() | |
| { | |
| return Bool () ? null : new T (); | |
| } | |
| static void Main (string[] args) | |
| { | |
| //expected Check<Test> but Check<Check<Test>> | |
| var getData = CheckMonad.Lift<Test> (GetData<Test>); | |
| var res = | |
| from a in getData () | |
| from b in getData () | |
| select a == b ? a : b; | |
| Console.WriteLine (res); | |
| Console.WriteLine ("finished!"); | |
| } | |
| } | |
| } | |
  
    
      This file contains hidden or 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
    
  
  
    
  | 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 Cast<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 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.IsFailed ? CheckM<TB>.Fail () : f (this.Value); | |
| } | |
| #endregion | |
| CheckM (T val) | |
| { | |
| Value = val; | |
| } | |
| public static CheckM<T> Success (T val) | |
| { | |
| return new CheckM<T> (val){ IsFailed = false }; | |
| } | |
| public static CheckM<T> Fail () | |
| { | |
| return new CheckM<T> (default(T)){ IsFailed = true }; | |
| } | |
| 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); | |
| } | |
| } | |
| } | |
| public static class CheckMonad | |
| { | |
| public static Func<Check.CheckM<TB>> Lift<TB> (this Func<TB> f) | |
| where TB : class | |
| { | |
| return () => { | |
| var res = f (); | |
| return res == null ? Check.CheckM<TB>.Fail () : Check.CheckM<TB>.Success (res); | |
| }; | |
| } | |
| } | |
| class MainClass | |
| { | |
| public static bool Bool () | |
| { | |
| return new Random ().Next () % 2 == 0; | |
| } | |
| public static T GetData<T> () | |
| where T : class, new() | |
| { | |
| return Bool () ? null : new T (); | |
| } | |
| static void Main (string[] args) | |
| { | |
| //expected Check<Test> but Check<Check<Test>> | |
| var getData = CheckMonad.Lift<Object> (GetData<Object>); | |
| var res = | |
| from a in getData () | |
| from b in getData () | |
| select a == b ? a : b; | |
| Check.CheckM<Object> m = res.Cast<Object, Check.CheckM<Object>, Check> (); | |
| Console.WriteLine (m); | |
| Console.WriteLine ("finished!"); | |
| } | |
| } | |
| } | |
  
    
      This file contains hidden or 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
    
  
  
    
  | 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 Cast<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 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.IsFailed ? CheckM<TB>.Fail () : f (this.Value); | |
| } | |
| #endregion | |
| CheckM (T val) | |
| { | |
| Value = val; | |
| } | |
| public static CheckM<T> Success (T val) | |
| { | |
| return new CheckM<T> (val){ IsFailed = false }; | |
| } | |
| public static CheckM<T> Fail () | |
| { | |
| return new CheckM<T> (default(T)){ IsFailed = true }; | |
| } | |
| 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); | |
| } | |
| } | |
| } | |
| public class CheckForT | |
| { | |
| CheckForT () | |
| { | |
| } | |
| public class CheckT<T,TMM>: CheckForT, IMonad<IMonad<T, TMM>, CheckForT> | |
| { | |
| #region IMonad implementation | |
| public IMonad<TB, CheckForT> Return<TB> (TB val) | |
| { | |
| return C | |
| } | |
| public IMonad<TB, CheckForT> Bind<TB> (Func<IMonad<T, TMM>, IMonad<TB, CheckForT>> f) | |
| { | |
| throw new NotImplementedException (); | |
| } | |
| #endregion | |
| CheckT (IMonad<T, TMM> val) | |
| { | |
| Value = val; | |
| } | |
| public static CheckT<T,TMM> Success (IMonad<T, TMM> val) | |
| { | |
| return new CheckT<T,TMM> (val){ IsFailed = false }; | |
| } | |
| public static CheckT<T,TMM> Fail () | |
| { | |
| return new CheckT<T,TMM> (default(IMonad<T, TMM>)){ IsFailed = true }; | |
| } | |
| public bool IsFailed { | |
| get; | |
| private set; | |
| } | |
| public IMonad<T, TMM> Value { | |
| get; | |
| private set; | |
| } | |
| public override string ToString () | |
| { | |
| return string.Format ("[Check: IsFailed={0}, Value={1}]", IsFailed, Value); | |
| } | |
| } | |
| } | |
| public static class CheckMonad | |
| { | |
| public static Func<Check.CheckM<TB>> Lift<TB> (this Func<TB> f) | |
| where TB : class | |
| { | |
| return () => { | |
| var res = f (); | |
| return res == null ? Check.CheckM<TB>.Fail () : Check.CheckM<TB>.Success (res); | |
| }; | |
| } | |
| } | |
| class MainClass | |
| { | |
| public static bool Bool () | |
| { | |
| return new Random ().Next () % 2 == 0; | |
| } | |
| public static T GetData<T> () | |
| where T : class, new() | |
| { | |
| return Bool () ? null : new T (); | |
| } | |
| static void Main (string[] args) | |
| { | |
| //expected Check<Test> but Check<Check<Test>> | |
| var getData = CheckMonad.Lift<Object> (GetData<Object>); | |
| var res = | |
| from a in getData () | |
| from b in getData () | |
| select a == b ? a : b; | |
| Check.CheckM<Object> m = res.Cast<Object, Check.CheckM<Object>, Check> (); | |
| Console.WriteLine (m); | |
| Console.WriteLine ("finished!"); | |
| } | |
| } | |
| } | 
  
    
      This file contains hidden or 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
    
  
  
    
  | using System; | |
| namespace MonadTutorial | |
| { | |
| class Tut | |
| { | |
| public static bool Bool () | |
| { | |
| return new Random ().Next () % 2 == 0 ? true : false; | |
| } | |
| public static T GetData<T> () | |
| where T : class, new() | |
| { | |
| return Bool () ? null : new T (); | |
| } | |
| public static void Compare (string[] args) | |
| { | |
| var a = GetData<Object> (); | |
| var b = GetData<Object> (); | |
| if (a == b) | |
| Console.WriteLine ("a == b"); | |
| else | |
| Console.WriteLine ("a != b"); | |
| Console.WriteLine ("finished!"); | |
| } | |
| public static void DefesiveCompare (string[] args) | |
| { | |
| var a = GetData<Object> (); | |
| if (a == null) { | |
| Console.WriteLine ("Can't compare"); | |
| return; | |
| } | |
| var b = GetData<Object> (); | |
| if (b == null) { | |
| Console.WriteLine ("Can't compare"); | |
| return; | |
| } | |
| if (a == b) | |
| Console.WriteLine ("a == b"); | |
| else | |
| Console.WriteLine ("a != b"); | |
| Console.WriteLine ("finished!"); | |
| } | |
| public static bool Defend (object o) | |
| { | |
| if (o == null) { | |
| Console.WriteLine ("Can't compare"); | |
| return false; | |
| } | |
| return true; | |
| } | |
| public static void DefesiveCompareDry (string[] args) | |
| { | |
| var a = GetData<Object> (); | |
| if (Defend (a)) | |
| return; | |
| var b = GetData<Object> (); | |
| if (Defend (b)) | |
| return; | |
| if (a == b) | |
| Console.WriteLine ("a == b"); | |
| else | |
| Console.WriteLine ("a != b"); | |
| Console.WriteLine ("finished!"); | |
| } | |
| public static string Defend2 (object a, Func<object, string> f) | |
| { | |
| return a == null ? "Can't compare" : f (a); | |
| } | |
| public static void DefesiveCompareDry2 (string[] args) | |
| { | |
| var res = Defend2 (GetData<Object> (), | |
| (a) => Defend2 (GetData<Object> (), | |
| (b) => a == b ? "a == b" : "a != b")); | |
| Console.WriteLine (res); | |
| Console.WriteLine ("finished!"); | |
| } | |
| class Test | |
| { | |
| public Test () | |
| { | |
| } | |
| } | |
| // public static TB Defend2Generic<TA,TB> (TA a, Func<TA, TB> f) | |
| // where TA : class//applied only for TA which can be null | |
| // { | |
| // return a == null ? "Can't compare" : f (a); | |
| // } | |
| public class Check<T> where T : class | |
| { | |
| public Check (String errorMessage) | |
| { | |
| IsFailed = true; | |
| FailMesssage = errorMessage; | |
| } | |
| public Check (T val) | |
| { | |
| Value = val; | |
| } | |
| public bool IsFailed { | |
| get; | |
| private set; | |
| } | |
| public string FailMesssage { | |
| get; | |
| private set; | |
| } | |
| public T Value { | |
| get; | |
| private set; | |
| } | |
| public override string ToString () | |
| { | |
| return string.Format ("[Check: IsFailed={0}, FailMesssage={1}, Value={2}]", IsFailed, FailMesssage, Value); | |
| } | |
| } | |
| public static Check<TB> Defend2Generic2<TA,TB> (TA a, Func<TA, TB> f) | |
| where TA : class | |
| where TB : class//applied only for TB and TA which can be null | |
| { | |
| return a == null ? new Check<TB> ("Can't compare") : new Check<TB> (f (a)); | |
| } | |
| // public static void DefesiveCompareGeneric2 (string[] args) | |
| // { | |
| // //expected Check<Test> but Check<Check<Test>> | |
| // Check<Test> res = Defend2Generic2 (GetData<Test> (), | |
| // a => Defend2Generic2 (GetData<Test> (), | |
| // b => a == b ? a : b)); | |
| // | |
| // Console.WriteLine (res); | |
| // Console.WriteLine ("finished!\n"); | |
| // } | |
| public class Check2<T> | |
| where T : class | |
| { | |
| private Check2 (T val) | |
| { | |
| Value = val; | |
| } | |
| public static Check2<T> Success (T val) | |
| { | |
| return new Check2<T> (val){ IsFailed = false }; | |
| } | |
| public static Check2<T> Fail () | |
| { | |
| return new Check2<T> (null){ IsFailed = true }; | |
| } | |
| public bool IsFailed { | |
| get; | |
| private set; | |
| } | |
| public T Value { | |
| get; | |
| private set; | |
| } | |
| public override string ToString () | |
| { | |
| return string.Format ("[Check: IsFailed={0}, Value={2}]", IsFailed, Value); | |
| } | |
| } | |
| public static Check2<TB> Defend2Generic3<TA,TB> (Check2<TA> a, Func<TA, Check2<TB>> f) | |
| where TA : class//applied only for TA which can be null | |
| where TB : class//applied only for TB which can be null | |
| { | |
| return a.IsFailed ? Check2<TB>.Fail () : f (a.Value); | |
| } | |
| public static Func<Check2<T>> Lift<T> (Func<T> f) | |
| where T : class | |
| { | |
| return () => { | |
| var res = f (); | |
| return res == null ? Check2<T>.Fail () : Check2<T>.Success (res); | |
| }; | |
| } | |
| // public static void DefesiveCompareGeneric3 (string[] args) | |
| // { | |
| // | |
| // var getData = Lift<Test> (GetData<Test>); | |
| // Check2<Test> res = Defend2Generic3<Test,Test> (getData (), | |
| // a => Defend2Generic3<Test,Test> (getData (), | |
| // b => a == b ? a : b)); | |
| // //unable to cast test to Check<Test> | |
| // Console.WriteLine (res); | |
| // Console.WriteLine ("finished!\n"); | |
| // } | |
| public class Check3<T> | |
| { | |
| private Check3 (T val) | |
| { | |
| Value = val; | |
| } | |
| public static Check3<T> Success (T val) | |
| { | |
| return new Check3<T> (val){ IsFailed = false }; | |
| } | |
| public static Check3<T> Fail () | |
| { | |
| return new Check3<T> (default(T)){ IsFailed = true }; | |
| } | |
| 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); | |
| } | |
| } | |
| public static Check3<TB> Defend2Generic4<TA,TB> (Check3<TA> a, Func<TA, Check3<TB>> f) | |
| { | |
| return a.IsFailed ? Check3<TB>.Fail () : f (a.Value); | |
| } | |
| public static Func<Check3<T>> Lift2<T> (Func<T> f) | |
| where T : class | |
| { | |
| return () => { | |
| var res = f (); | |
| return res == null ? Check3<T>.Fail () : Check3<T>.Success (res); | |
| }; | |
| } | |
| public static Check3<T> Return <T> (T val) | |
| { | |
| return Check3<T>.Success (val); | |
| } | |
| public static void DefesiveCompareGeneric4 (string[] args) | |
| { | |
| //expected Check<Test> but Check<Check<Test>> | |
| var getData = Lift2<Test> (GetData<Test>); | |
| Check3<Test> res = Defend2Generic4<Test,Test> (getData (), | |
| a => Defend2Generic4<Test,Test> (getData (), | |
| b => Return (a == b ? a : b))); | |
| Console.WriteLine (res); | |
| Console.WriteLine ("finished!"); | |
| } | |
| //generalization | |
| // interface IMonad<T> | |
| // { | |
| // TB Bind<TMA,TMB,TA,TB> (TMA a, Func<TA, TMB> f) | |
| // where TMA : IMonad<TA> | |
| // where TMB : IMonad<TB>; | |
| // } | |
| // | |
| // class CheckM<T> : IMonad<T> | |
| // { | |
| // T _obj; | |
| // | |
| // private CheckM (T obj) | |
| // { | |
| // _obj = obj; | |
| // } | |
| // | |
| // public TB Bind<TA, TB> (Check<TA> a, Func<TA, TB> f) | |
| // { | |
| // throw new NotImplementedException (); | |
| // } | |
| // } | |
| } | |
| } | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment