public static TMonad Bind <TMonad>(TMonad a, TMonad b, Func <object, object, TMonad> f, IMonad <TMonad> m) { return(m.Bind(a, Bind)); TMonad Bind(object av) { return(m.Bind(b, Bind2)); TMonad Bind2(object bv) { return(f(av, bv)); } } }
/// <summary></summary> public static IMonad <T> Do <T>(this IMonad <T> monad, Action <T> action) => monad.Bind( v => { action(v); return(monad); });
/// <summary> /// Extracts the value(s) from the source and replaces it with another one, ignoring the values of the source. /// </summary> /// <typeparam name="TSource">The type of the source.</typeparam> /// <typeparam name="TResult">The type of the result.</typeparam> /// <param name="a">The value containing the source.</param> /// <param name="b">The value containing the result.</param> public static IMonad <TResult> Then <TSource, TResult>(this IMonad <TSource> a, IMonad <TResult> b) => a.Bind(x => b);
/// <summary> /// A more readable alias to <see cref="IMonad{TSource}.Bind{TResult}(Func{TSource, IMonad{TResult}})"/>. /// </summary> /// <typeparam name="TSource">The type of the source.</typeparam> /// <typeparam name="TResult">The type of the result.</typeparam> /// <param name="a">The value containing the source.</param> /// <param name="f">The function to apply.</param> public static IMonad <TResult> Then <TSource, TResult>(this IMonad <TSource> a, Func <TSource, IMonad <TResult> > f) => a.Bind(f);
/// <summary> /// Flattens the structure of a monad. The following holds for all X and f, given a correctly implemented /// <see cref="IFunctor{TSource}.Map{TResult}(Func{TSource, TResult})"/> and /// <see cref="IMonad{TSource}.Bind{TResult}(Func{TSource, IMonad{TResult}})"/>: /// <code> /// X.Map(x => x.Join()).Join() = X.Join().Join() /// X.Map(x => x.Pure()).Join() = X.Pure().Join() = id /// X.Map(x => x.Map(f)).Join() = X.Join().Map(f) /// </code> /// </summary> /// <typeparam name="T">The type in the monad.</typeparam> /// <param name="a">The monad to flatten.</param> /// <returns></returns> public static IMonad <T> Join <T>(this IMonad <IMonad <T> > a) => a.Bind(x => x);
/// <summary> /// Equivalent to <see cref="IMonad{TSource}"/>. The monad-type is preserved, but checking that every computation in the query is in the same monad, and checking for a concrete type are the responsibility of the caller. /// Offers LINQ query support with multiple <c>from</c>-clauses. /// </summary> /// <typeparam name="TSource">The type of the source's value.</typeparam> /// <typeparam name="TMiddle">The type of the selector's result.</typeparam> /// <typeparam name="TResult">The type of the result's value.</typeparam> /// <param name="source">The source.</param> /// <param name="f">The function to apply.</param> /// <param name="resultSelector">The result-selector.</param> public static IMonad <TResult> SelectMany <TSource, TMiddle, TResult> (this IMonad <TSource> source, Func <TSource, IMonad <TMiddle> > f, Func <TSource, TMiddle, TResult> resultSelector) => source.Bind(x => (IMonad <TResult>)f(x).Map(y => resultSelector(x, y)));
public static IMonad <B> Bind <A, B>(this Func <A, IMonad <B> > f, IMonad <A> a) => a.Bind(f);