Category Theory via C# (6) Monoidal Functor and Applicative Functor

[LINQ via C# series]

[Category Theory via C# series]

Monoidal functor

Given monoidal categories (C, ⊗, IC) and (D, ⊛, ID), a strong lax monoidal functor is a functor F: C → D equipped with:

  • Monoid binary multiplication operation, which is a natural transformation φ: F(X) ⊛ F(Y) ⇒ F(X ⊗ Y)
  • Monoid unit, which is a morphism ι: ID → F(IC)

F preserves the monoid laws in D:

  • Associativity law is preserved with D’s associator αD:
    Untitled-4.fw_thumb1
  • Left unit law is preserved with D’s left unitor λD:
    image_thumb 
    and right unit law is preserved with D’s right unitor ρD:
    Untitled-3..fw_thumb 

In this tutorial, strong lax monoidal functor is called monoidal functor for short. In DotNet category, monoidal functors are monoidal endofunctors. In the definition, (C, ⊗, IC) and (D, ⊛, ID) are both (DotNet, ValueTuple<,>, Unit), so monoidal functor can be IEnumerable<T1>, IEnumerable<T2>defined as:

public interface IMonoidalFunctor<TMonoidalFunctor<>> : IFunctor<TMonoidalFunctor<>>
    where TMonoidalFunctor : IMonoidalFunctor<TMonoidalFunctor<>>
{
    // From IFunctor<TMonoidalFunctor<>>:
    // Select: (TSource -> TResult) -> (TMonoidalFunctor<TSource> -> TMonoidalFunctor<TResult>)
    // Func<TMonoidalFunctor<TSource>, TMonoidalFunctor<TResult>> Select<TSource, TResult>(Func<TSource, TResult> selector);

    // Multiply: TMonoidalFunctor<T1> x TMonoidalFunctor<T2> -> TMonoidalFunctor<T1 x T2>
    // Multiply: ValueTuple<TMonoidalFunctor<T1>, TMonoidalFunctor<T2>> -> TMonoidalFunctor<ValueTuple<T1, T2>>
    TMonoidalFunctor<ValueTuple<T1, T2>> Multiply<T1, T2>(
        ValueTuple<TMonoidalFunctor<T1>, TMonoidalFunctor<T2>> bifunctor);

    // Unit: Unit -> TMonoidalFunctor<Unit>
    TMonoidalFunctor<Unit> Unit(Unit unit);
}

Multiply accepts a ValueTuple<IEnumerable<T1>, IEnumerable<T2>> bifunctor, which is literally a 2-tuple (IEnumerable<T1>, IEnumerable<T2>). For convenience, the explicit ValueTuple<,> parameter can be represented by an implicit tuple, a pair of parameters. So the monoidal functor definition is equivalent to:

public interface IMonoidalFunctor<TMonoidalFunctor<>> : IFunctor<TMonoidalFunctor<>>
    where TMonoidalFunctor : IMonoidalFunctor<TMonoidalFunctor<>>
{
    // Multiply: TMonoidalFunctor<T1> x TMonoidalFunctor<T2> -> TMonoidalFunctor<T1 x T2>
    // Multiply: (TMonoidalFunctor<T1>, TMonoidalFunctor<T2>) -> TMonoidalFunctor<(T1, T2)>
    TMonoidalFunctor<(T1, T2)> Multiply<T1, T2>(
        TMonoidalFunctor<T1> source1, TMonoidalFunctor<T2>> source2); // Unit: Unit

    // Unit: Unit -> TMonoidalFunctor<Unit>
    TMonoidalFunctor<Unit> Unit(Unit unit);
}

IEnumerable<> monoidal functor

IEnumerable<> functor is a monoidal functor. Its Multiply method can be implemented as its extension method:

public static partial class EnumerableExtensions // IEnumerable<T> : IMonoidalFunctor<IEnumerable<>>
{
    // Multiply: IEnumerable<T1> x IEnumerable<T2> -> IEnumerable<T1 x T2>
    // Multiply: ValueTuple<IEnumerable<T1>, IEnumerable<T2>> -> IEnumerable<ValueTuple<T1, T2>>
    // Multiply: (IEnumerable<T1>, IEnumerable<T2>) -> IEnumerable<(T1, T2)>
    public static IEnumerable<(T1, T2)> Multiply<T1, T2>(
        this IEnumerable<T1> source1, IEnumerable<T2> source2) // Implicit tuple.
    {
        foreach (T1 value1 in source1)
        {
            foreach (T2 value2 in source2)
            {
                yield return (value1, value2);
            }
        }
    }

    // Unit: Unit -> IEnumerable<Unit>
    public static IEnumerable<Unit> Unit(Unit unit = default)
    {
        yield return unit;
    }
}

Now extension method Multiply can be used as a infix operator. It can be verified that the above Multiply and Unit implementations preserve the monoid laws by working with associator, left unitor and right unitor of DotNet monoidal category:

// using static Dixin.Linq.CategoryTheory.DotNetCategory;
internal static void MonoidalFunctorLaws()
{
    IEnumerable<Unit> unit = Unit();
    IEnumerable<int> source1 = new int[] { 0, 1 };
    IEnumerable<char> source2 = new char[] { '@', '#' };
    IEnumerable<bool> source3 = new bool[] { true, false };
    IEnumerable<int> source = new int[] { 0, 1, 2, 3, 4 };

    // Associativity preservation: source1.Multiply(source2).Multiply(source3).Select(Associator) == source1.Multiply(source2.Multiply(source3)).
    source1.Multiply(source2).Multiply(source3).Select(Associator).WriteLines();
        // (0, (@, True)) (0, (@, False)) (0, (#, True)) (0, (#, False))
        // (1, (@, True)) (1, (@, False)) (1, (#, True)) (1, (#, False))
    source1.Multiply(source2.Multiply(source3)).WriteLines();
        // (0, (@, True)) (0, (@, False)) (0, (#, True)) (0, (#, False))
        // (1, (@, True)) (1, (@, False)) (1, (#, True)) (1, (#, False))
    // Left unit preservation: unit.Multiply(source).Select(LeftUnitor) == source.
    unit.Multiply(source).Select(LeftUnitor).WriteLines(); // 0 1 2 3 4
    // Right unit preservation: source == source.Multiply(unit).Select(RightUnitor).
    source.Multiply(unit).Select(RightUnitor).WriteLines(); // 0 1 2 3 4
}

How could these methods be useful? Remember functor’s Select method enables selector working with value(s) wrapped by functor:

internal static void Selector1Arity(IEnumerable<int> xs)
{
    Func<int, bool> selector = x => x > 0;
    // Apply selector with xs.
    IEnumerable<bool> applyWithXs = xs.Select(selector);
}

So Select can be viewed as applying 1 arity selector (a TSource –> TResult function) with TFunctor<TSource>. For a N arity selector, to have it work with value(s) wrapped by functor, first curry it, so that it can be viewed as 1 arity function. In the following example, the (T1, T2, T3) –> TResult selector is curried to T1 –> (T2 –> T3 –> TResult) function, so that it can be viewed as only have 1 parameter, and can work with TFunctor<T1>:

internal static void SelectorNArity(IEnumerable<int> xs, IEnumerable<long> ys, IEnumerable<double> zs)
{
    Func<int, long, double, bool> selector = (x, y, z) => x + y + z > 0;

    // Curry selector.
    Func<int, Func<long, Func<double, bool>>> curriedSelector = 
        selector.Curry(); // 1 arity: x => (y => z => x + y + z > 0)
    // Partially apply selector with xs.
    IEnumerable<Func<long, Func<double, bool>>> applyWithXs = xs.Select(curriedSelector);

So partially applying the T1 –> (T2 –> T3 –> TResult) selector with TFunctor<T1> returns TFunctor<T2 –> T3 –> TResult>, where the T2 –> T3 –> TResult function is wrapped by the TFunctor<> functor. To further apply TFunctor<T2 –> T3 –> TResult> with TFunctor<T2>, Multiply can be called:

    // Partially apply selector with ys.
    IEnumerable<(Func<long, Func<double, bool>>, long)> multiplyWithYs = applyWithXs.Multiply(ys);
    IEnumerable<Func<double, bool>> applyWithYs = multiplyWithYs.Select(product =>
    {
        Func<long, Func<double, bool>> partialAppliedSelector = product.Item1;
        long y = product.Item2;
        return partialAppliedSelector(y);
    });

The result of Multiply is TFunctor<(T2 –> T3 –> TResult, T2)>, where each T2 –> T3 –> TResult function is paired with each T2 value, so that each function can be applied with each value, And TFunctor<(T2 –> T3 –> TResult, T2)> is mapped to TFunctor<(T3 –> TResult)>, which can be applied with TFunctor<T3> in the same way:

    // Partially apply selector with zs.
    IEnumerable<(Func<double, bool>, double)> multiplyWithZs = applyWithYs.Multiply(zs);
    IEnumerable<bool> applyWithZs = multiplyWithZs.Select(product =>
    {
        Func<double, bool> partialAppliedSelector = product.Item1;
        double z = product.Item2;
        return partialAppliedSelector(z);
    });
}

So Multiply enables applying functor-wrapped functions (TFunctor<T –> TResult>) with functor-wrapped values (TFunctor<TSource>), which returns functor-wrapped results (TFunctor<TResult>). Generally, the Multiply and Select calls can be encapsulated as the following Apply method:

// Apply: (IEnumerable<TSource -> TResult>, IEnumerable<TSource>) -> IEnumerable<TResult>
public static IEnumerable<TResult> Apply<TSource, TResult>(
    this IEnumerable<Func<TSource, TResult>> selectorWrapper, IEnumerable<TSource> source) =>
        selectorWrapper.Multiply(source).Select(product => product.Item1(product.Item2));

So that the above N arity selector application becomes:

internal static void Apply(IEnumerable<int> xs, IEnumerable<long> ys, IEnumerable<double> zs)
{
    Func<int, long, double, bool> selector = (x, y, z) => x + y + z > 0;
    // Partially apply selector with xs.
    IEnumerable<Func<long, Func<double, bool>>> applyWithXs = xs.Select(selector.Curry());
    // Partially apply selector with ys.
    IEnumerable<Func<double, bool>> applyWithYs = applyWithXs.Apply(ys);
    // Partially apply selector with zs.
    IEnumerable<bool> applyWithZs = applyWithYs.Apply(zs);
}

Applicative functor

A functor, with the above ability to apply functor-wrapped functions with functor-wrapped values, is also called applicative functor. The following is the definition of applicative functor:

// Cannot be compiled.
public interface IApplicativeFunctor<TApplicativeFunctor<>> : IFunctor<TApplicativeFunctor<>>
    where TApplicativeFunctor<> : IApplicativeFunctor<TApplicativeFunctor<>>
{
    // From: IFunctor<TApplicativeFunctor<>>:
    // Select: (TSource -> TResult) -> (TApplicativeFunctor<TSource> -> TApplicativeFunctor<TResult>)
    // Func<TApplicativeFunctor<TSource>, TApplicativeFunctor<TResult>> Select<TSource, TResult>(Func<TSource, TResult> selector);

    // Apply: (TApplicativeFunctor<TSource -> TResult>, TApplicativeFunctor<TSource> -> TApplicativeFunctor<TResult>
    TApplicativeFunctor<TResult> Apply<TSource, TResult>(
        TApplicativeFunctor<Func<TSource, TResult>> selectorWrapper, TApplicativeFunctor<TSource> source);

    // Wrap: TSource -> TApplicativeFunctor<TSource>
    TApplicativeFunctor<TSource> Wrap<TSource>(TSource value);
}

And applicative functor must satisfy the applicative laws:

  • Functor preservation: applying function is equivalent to applying functor-wrapped function
  • Identity preservation: applying functor-wrapped identity function, is equivalent to doing nothing.
  • Composition preservation: functor-wrapped functions can be composed by applying.
  • Homomorphism: applying functor-wrapped function with functor-wrapped value, is equivalent to functor-wrapping the result of applying that function with that value.
  • Interchange: when applying functor-wrapped functions with a functor-wrapped value, the functor-wrapped functions and the functor-wrapped value can interchange position.

IEnumerable<> applicative functor

IEnumerable<> functor is a applicative functor. Again, these methods are implemented as extension methods. And for IEnumerable<>, the Wrap method is called Enumerable to be intuitive:

public static partial class EnumerableExtensions // IEnumerable<T> : IApplicativeFunctor<IEnumerable<>>
{
    // Apply: (IEnumerable<TSource -> TResult>, IEnumerable<TSource>) -> IEnumerable<TResult>
    public static IEnumerable<TResult> Apply<TSource, TResult>(
        this IEnumerable<Func<TSource, TResult>> selectorWrapper, IEnumerable<TSource> source)
    {
        foreach (Func<TSource, TResult> selector in selectorWrapper)
        {
            foreach (TSource value in source)
            {
                yield return selector(value);
            }
        }
    }

    // Wrap: TSource -> IEnumerable<TSource>
    public static IEnumerable<TSource> Enumerable<TSource>(this TSource value)
    {
        yield return value;
    }
}

It can be verified that the above Apply and Wrap (Enumerable) implementations satisfy the applicative laws:

internal static void ApplicativeLaws()
{
    IEnumerable<int> source = new int[] { 0, 1, 2, 3, 4 };
    Func<int, double> selector = int32 => Math.Sqrt(int32);
    IEnumerable<Func<int, double>> selectorWrapper1 =
        new Func<int, double>[] { int32 => int32 / 2D, int32 => Math.Sqrt(int32) };
    IEnumerable<Func<double, string>> selectorWrapper2 =
        new Func<double, string>[] { @double => @double.ToString("0.0"), @double => @double.ToString("0.00") };
    Func<Func<double, string>, Func<Func<int, double>, Func<int, string>>> o =
        new Func<Func<double, string>, Func<int, double>, Func<int, string>>(Linq.FuncExtensions.o).Curry();
    int value = 5;

    // Functor preservation: source.Select(selector) == selector.Wrap().Apply(source).
    source.Select(selector).WriteLines(); // 0 1 1.4142135623731 1.73205080756888 2
    selector.Enumerable().Apply(source).WriteLines(); // 0 1 1.4142135623731 1.73205080756888 2
    // Identity preservation: Id.Wrap().Apply(source) == source.
    new Func<int, int>(Functions.Id).Enumerable().Apply(source).WriteLines(); // 0 1 2 3 4
    // Composition preservation: o.Wrap().Apply(selectorWrapper2).Apply(selectorWrapper1).Apply(source) == selectorWrapper2.Apply(selectorWrapper1.Apply(source)).
    o.Enumerable().Apply(selectorWrapper2).Apply(selectorWrapper1).Apply(source).WriteLines();
        // 0.0  0.5  1.0  1.5  2.0
        // 0.0  1.0  1.4  1.7  2.0 
        // 0.00 0.50 1.00 1.50 2.00
        // 0.00 1.00 1.41 1.73 2.00
    selectorWrapper2.Apply(selectorWrapper1.Apply(source)).WriteLines();
        // 0.0  0.5  1.0  1.5  2.0
        // 0.0  1.0  1.4  1.7  2.0 
        // 0.00 0.50 1.00 1.50 2.00
        // 0.00 1.00 1.41 1.73 2.00
    // Homomorphism: selector.Wrap().Apply(value.Wrap()) == selector(value).Wrap().
    selector.Enumerable().Apply(value.Enumerable()).WriteLines(); // 2.23606797749979
    selector(value).Enumerable().WriteLines(); // 2.23606797749979
    // Interchange: selectorWrapper.Apply(value.Wrap()) == (selector => selector(value)).Wrap().Apply(selectorWrapper).
    selectorWrapper1.Apply(value.Enumerable()).WriteLines(); // 2.5 2.23606797749979
    new Func<Func<int, double>, double>(function => function(value)).Enumerable().Apply(selectorWrapper1)
        .WriteLines(); // 2.5 2.23606797749979
}

Monoidal functor vs. applicative functor

The applicative functor definition is actually equivalent to above monoidal functor definition. First, applicative functor’s Apply and Wrap methods can be implemented by monoidal functor’s Multiply and Unit methods:

public static partial class EnumerableExtensions // IEnumerable<T> : IApplicativeFunctor<IEnumerable<>>
{
    // Apply: (IEnumerable<TSource -> TResult>, IEnumerable<TSource>) -> IEnumerable<TResult>
    public static IEnumerable<TResult> Apply<TSource, TResult>(
        this IEnumerable<Func<TSource, TResult>> selectorWrapper, IEnumerable<TSource> source) =>
            selectorWrapper.Multiply(source).Select(product => product.Item1(product.Item2));

    // Wrap: TSource -> IEnumerable<TSource>
    public static IEnumerable<TSource> Enumerable<TSource>(this TSource value) => Unit().Select(unit => value);
}

On the other hand, monoidal functor’s Multiply and Unit methods can be implemented by applicative functor’s Apply and Wrap methods:

public static partial class EnumerableExtensions // IEnumerable<T> : IMonoidalFunctor<IEnumerable<>>
{
    // Multiply: IEnumerable<T1> x IEnumerable<T2> -> IEnumerable<T1 x T2>
    // Multiply: (IEnumerable<T1>, IEnumerable<T2>) -> IEnumerable<(T1, T2)>
    public static IEnumerable<(T1, T2)> Multiply<T1, T2>(
        this IEnumerable<T1> source1, IEnumerable<T2> source2) =>
            new Func<T1, T2, (T1, T2)>(ValueTuple.Create).Curry().Enumerable().Apply(source1).Apply(source2);

    // Unit: Unit -> IEnumerable<Unit>
    public static IEnumerable<Unit> Unit(Unit unit = default) => unit.Enumerable();
}

Generally, for any applicative functor, its (Apply, Wrap) method pair can implement the (Multiply, Unit) method pair required as monoidal functor, and vice versa. This can be virtually demonstrated as:

// Cannot be compiled.
public static class MonoidalFunctorExtensions // (Multiply, Unit) implements (Apply, Wrap).
{
    // Apply: (TMonoidalFunctor<TSource -> TResult>, TMonoidalFunctor<TSource>) -> TMonoidalFunctor<TResult>
    public static TMonoidalFunctor<TResult> Apply<TMonoidalFunctor<>, TSource, TResult>(
        this TMonoidalFunctor<Func<TSource, TResult>> selectorWrapper, TMonoidalFunctor<TSource> source) 
        where TMonoidalFunctor<> : IMonoidalFunctor<TMonoidalFunctor<>> =>
            selectorWrapper.Multiply(source).Select(product => product.Item1(product.Item2));

    // Wrap: TSource -> TMonoidalFunctor<TSource>
    public static TMonoidalFunctor<TSource> Wrap<TMonoidalFunctor<>, TSource>(this TSource value) 
        where TMonoidalFunctor<> : IMonoidalFunctor<TMonoidalFunctor<>> =>TMonoidalFunctor<TSource>
            TMonoidalFunctor<TSource>.Unit().Select(unit => value);
}

// Cannot be compiled.
public static class ApplicativeFunctorExtensions // (Apply, Wrap) implements (Multiply, Unit).
{
    // Multiply: TApplicativeFunctor<T1> x TApplicativeFunctor<T2> -> TApplicativeFunctor<T1 x T2>
    // Multiply: (TApplicativeFunctor<T1>, TApplicativeFunctor<T2>) -> TApplicativeFunctor<(T1, T2)>
    public static TApplicativeFunctor<(T1, T2)> Multiply<TApplicativeFunctor<>, T1, T2>(
        this TApplicativeFunctor<T1> source1, TApplicativeFunctor<T2> source2) 
        where TApplicativeFunctor<> : IApplicativeFunctor<TApplicativeFunctor<>> =>
            new Func<T1, T2, (T1, T2)>(ValueTuple.Create).Curry().Wrap().Apply(source1).Apply(source2);

    // Unit: Unit -> TApplicativeFunctor<Unit>
    public static TApplicativeFunctor<Unit> Unit<TApplicativeFunctor<>>(Unit unit = default)
        where TApplicativeFunctor<> : IApplicativeFunctor<TApplicativeFunctor<>> => unit.Wrap();
}

More Monoidal functors and applicative functors

The Lazy<>, Func<>, Func<T,> functors are also monoidal/applicative functors:

public static partial class LazyExtensions // Lazy<T> : IMonoidalFunctor<Lazy<>>
{
    // Multiply: Lazy<T1> x Lazy<T2> -> Lazy<T1 x T2>
    // Multiply: (Lazy<T1>, Lazy<T2>) -> Lazy<(T1, T2)>
    public static Lazy<(T1, T2)> Multiply<T1, T2>(this Lazy<T1> source1, Lazy<T2> source2) =>
        new Lazy<(T1, T2)>(() => (source1.Value, source2.Value));

    // Unit: Unit -> Lazy<Unit>
    public static Lazy<Unit> Unit(Unit unit = default) => new Lazy<Unit>(() => unit);
}

public static partial class LazyExtensions // Lazy<T> : IApplicativeFunctor<Lazy<>>
{
    // Apply: (Lazy<TSource -> TResult>, Lazy<TSource>) -> Lazy<TResult>
    public static Lazy<TResult> Apply<TSource, TResult>(
        this Lazy<Func<TSource, TResult>> selectorWrapper, Lazy<TSource> source) =>
            selectorWrapper.Multiply(source).Select(product => product.Item1(product.Item2));

    // Wrap: TSource -> Lazy<TSource>
    public static Lazy<T> Lazy<T>(this T value) => Unit().Select(unit => value);
}

public static partial class FuncExtensions // Func<T> : IMonoidalFunctor<Func<>>
{
    // Multiply: Func<T1> x Func<T2> -> Func<T1 x T2>
    // Multiply: (Func<T1>, Func<T2>) -> Func<(T1, T2)>
    public static Func<(T1, T2)> Multiply<T1, T2>(this Func<T1> source1, Func<T2> source2) =>
        () => (source1(), source2());

    // Unit: Unit -> Func<Unit>
    public static Func<Unit> Unit(Unit unit = default) => () => unit;
}

public static partial class FuncExtensions // Func<T> : IApplicativeFunctor<Func<>>
{
    // Apply: (Func<TSource -> TResult>, Func<TSource>) -> Func<TResult>
    public static Func<TResult> Apply<TSource, TResult>(
        this Func<Func<TSource, TResult>> selectorWrapper, Func<TSource> source) =>
            selectorWrapper.Multiply(source).Select(product => product.Item1(product.Item2));

    // Wrap: TSource -> Func<TSource>
    public static Func<T> Func<T>(this T value) => Unit().Select(unit => value);
}

public static partial class FuncExtensions // Func<T, TResult> : IMonoidalFunctor<Func<T,>>
{
    // Multiply: Func<T, T1> x Func<T, T2> -> Func<T, T1 x T2>
    // Multiply: (Func<T, T1>, Func<T, T2>) -> Func<T, (T1, T2)>
    public static Func<T, (T1, T2)> Multiply<T, T1, T2>(this Func<T, T1> source1, Func<T, T2> source2) =>
        value => (source1(value), source2(value));

    // Unit: Unit -> Func<T, Unit>
    public static Func<T, Unit> Unit<T>(Unit unit = default) => _ => unit;
}

public static partial class FuncExtensions // Func<T, TResult> : IApplicativeFunctor<Func<T,>>
{
    // Apply: (Func<T, TSource -> TResult>, Func<T, TSource>) -> Func<T, TResult>
    public static Func<T, TResult> Apply<T, TSource, TResult>(
        this Func<T, Func<TSource, TResult>> selectorWrapper, Func<T, TSource> source) =>
            selectorWrapper.Multiply(source).Select(product => product.Item1(product.Item2));

    // Wrap: TSource -> Func<T, TSource>
    public static Func<T, TSource> Func<T, TSource>(this TSource value) => Unit<T>().Select(unit => value);
}

public static partial class OptionalExtensions // Optional<T> : IMonoidalFunctor<Optional<>>
{
    // Multiply: Optional<T1> x Optional<T2> -> Optional<T1 x T2>
    // Multiply: (Optional<T1>, Optional<T2>) -> Optional<(T1, T2)>
    public static Optional<(T1, T2)> Multiply<T1, T2>(this Optional<T1> source1, Optional<T2> source2) =>
        new Optional<(T1, T2)>(() => source1.HasValue && source2.HasValue
            ? (true, (source1.Value, source2.Value))
            : (false, (default, default)));

    // Unit: Unit -> Optional<Unit>
    public static Optional<Unit> Unit(Unit unit = default) =>
        new Optional<Unit>(() => (true, unit));
}

public static partial class OptionalExtensions // Optional<T> : IApplicativeFunctor<Optional<>>
{
    // Apply: (Optional<TSource -> TResult>, Optional<TSource>) -> Optional<TResult>
    public static Optional<TResult> Apply<TSource, TResult>(
        this Optional<Func<TSource, TResult>> selectorWrapper, Optional<TSource> source) =>
            selectorWrapper.Multiply(source).Select(product => product.Item1(product.Item2));

    // Wrap: TSource -> Optional<TSource>
    public static Optional<T> Optional<T>(this T value) => Unit().Select(unit => value);
}

The ValueTuple<> and Task<> functors are monoidal/applicative functors too. Notice their Multiply/Apply methods cannot defer the execution, and Task<>’s Multiply/Apply methods are impure.

public static partial class ValueTupleExtensions // ValueTuple<T> : IMonoidalFunctor<ValueTuple<>>
{
    // Multiply: ValueTuple<T1> x ValueTuple<T2> -> ValueTuple<T1 x T2>
    // Multiply: (ValueTuple<T1>, ValueTuple<T2>) -> ValueTuple<(T1, T2)>
    public static ValueTuple<(T1, T2)> Multiply<T1, T2>(this ValueTuple<T1> source1, ValueTuple<T2> source2) =>
        new ValueTuple<(T1, T2)>((source1.Item1, source2.Item1)); // Immediate execution.

    // Unit: Unit -> ValueTuple<Unit>
    public static ValueTuple<Unit> Unit(Unit unit = default) => new ValueTuple<Unit>(unit);
}

public static partial class ValueTupleExtensions // ValueTuple<T> : IApplicativeFunctor<ValueTuple<>>
{
    // Apply: (ValueTuple<TSource -> TResult>, ValueTuple<TSource>) -> ValueTuple<TResult>
    public static ValueTuple<TResult> Apply<TSource, TResult>(
        this ValueTuple<Func<TSource, TResult>> selectorWrapper, ValueTuple<TSource> source) =>
            selectorWrapper.Multiply(source).Select(product => product.Item1(product.Item2)); // Immediate execution.

    // Wrap: TSource -> ValueTuple<TSource>
    public static ValueTuple<T> ValueTuple<T>(this T value) => Unit().Select(unit => value);
}

public static partial class TaskExtensions // Task<T> : IMonoidalFunctor<Task<>>
{
    // Multiply: Task<T1> x Task<T2> -> Task<T1 x T2>
    // Multiply: (Task<T1>, Task<T2>) -> Task<(T1, T2)>
    public static async Task<(T1, T2)> Multiply<T1, T2>(this Task<T1> source1, Task<T2> source2) =>
        ((await source1), (await source2)); // Immediate execution, impure.

    // Unit: Unit -> Task<Unit>
    public static Task<Unit> Unit(Unit unit = default) => System.Threading.Tasks.Task.FromResult(unit);
}

public static partial class TaskExtensions // Task<T> : IApplicativeFunctor<Task<>>
{
    // Apply: (Task<TSource -> TResult>, Task<TSource>) -> Task<TResult>
    public static Task<TResult> Apply<TSource, TResult>(
        this Task<Func<TSource, TResult>> selectorWrapper, Task<TSource> source) =>
            selectorWrapper.Multiply(source).Select(product => product.Item1(product.Item2)); // Immediate execution, impure.

    // Wrap: TSource -> Task<TSource>
    public static Task<T> Task<T>(this T value) => Unit().Select(unit => value);
}

It is easy to verify all the above (Multiply, Unit) method pairs preserve the monoid laws, and all the above (Apply, Wrap) method pairs satisfy the applicative laws. However, not any (Multiply, Unit) or any (Apply, Wrap) can automatically satisfy the laws. Take the ValueTuple<T,> functor as example:

public static partial class ValueTupleExtensions // ValueTuple<T1, T2 : IMonoidalFunctor<ValueTuple<T,>>
{
    // Multiply: ValueTuple<T, T1> x ValueTuple<T, T2> -> ValueTuple<T, T1 x T2>
    // Multiply: (ValueTuple<T, T1>, ValueTuple<T, T2>) -> ValueTuple<T, (T1, T2)>
    public static (T, (T1, T2)) Multiply<T, T1, T2>(this (T, T1) source1, (T, T2) source2) =>
        (source1.Item1, (source1.Item2, source2.Item2)); // Immediate execution.

    // Unit: Unit -> ValueTuple<Unit>
    public static (T, Unit) Unit<T>(Unit unit = default) => (default, unit);
}

public static partial class ValueTupleExtensions // ValueTuple<T, TResult> : IApplicativeFunctor<ValueTuple<T,>>
{
    // Apply: (ValueTuple<T, TSource -> TResult>, ValueTuple<T, TSource>) -> ValueTuple<T, TResult>
    public static (T, TResult) Apply<T, TSource, TResult>(
        this (T, Func<TSource, TResult>) selectorWrapper, (T, TSource) source) =>
            selectorWrapper.Multiply(source).Select(product => product.Item1(product.Item2)); // Immediate execution.

    // Wrap: TSource -> ValueTuple<T, TSource>
    public static (T, TSource) ValueTuple<T, TSource>(this TSource value) => Unit<T>().Select(unit => value);
}

The above (Multiply, Unit) implementations cannot preserve the left unit law:

internal static void MonoidalFunctorLaws()
{
    (string, int) source = ("a", 1);
    (string, Unit) unit = Unit<string>();
    (string, int) source1 = ("b", 2);
    (string, char) source2 = ("c", '@');
    (string, bool) source3 = ("d", true);

    // Associativity preservation: source1.Multiply(source2).Multiply(source3).Select(Associator) == source1.Multiply(source2.Multiply(source3)).
    source1.Multiply(source2).Multiply(source3).Select(Associator).WriteLine(); // (b, (2, (@, True)))
    source1.Multiply(source2.Multiply(source3)).WriteLine(); // (b, (2, (@, True)))
    // Left unit preservation: unit.Multiply(source).Select(LeftUnitor) == source.
    unit.Multiply(source).Select(LeftUnitor).WriteLine(); // (, 1)
    // Right unit preservation: source == source.Multiply(unit).Select(RightUnitor).
    source.Multiply(unit).Select(RightUnitor).WriteLine(); // (a, 1)
}

And the above (Apply, Wrap) implementation breaks all applicative laws:

internal static void ApplicativeLaws()
{
    (string, int) source = ("a", 1);
    Func<int, double> selector = int32 => Math.Sqrt(int32);
    (string, Func<int, double>) selectorWrapper1 = 
        ("b", new Func<int, double>(int32 => Math.Sqrt(int32)));
    (string, Func<double, string>) selectorWrapper2 =
        ("c", new Func<double, string>(@double => @double.ToString("0.00")));
    Func<Func<double, string>, Func<Func<int, double>, Func<int, string>>> o = 
        new Func<Func<double, string>, Func<int, double>, Func<int, string>>(Linq.FuncExtensions.o).Curry();
    int value = 5;

    // Functor preservation: source.Select(selector) == selector.Wrap().Apply(source).
    source.Select(selector).WriteLine(); // (a, 1)
    selector.ValueTuple<string, Func<int, double>>().Apply(source).WriteLine(); // (, 1)
    // Identity preservation: Id.Wrap().Apply(source) == source.
    new Func<int, int>(Functions.Id).ValueTuple<string, Func<int, int>>().Apply(source).WriteLine(); // (, 1)
    // Composition preservation: o.Curry().Wrap().Apply(selectorWrapper2).Apply(selectorWrapper1).Apply(source) == selectorWrapper2.Apply(selectorWrapper1.Apply(source)).
    o.ValueTuple<string, Func<Func<double, string>, Func<Func<int, double>, Func<int, string>>>>()
        .Apply(selectorWrapper2).Apply(selectorWrapper1).Apply(source).WriteLine(); // (, 1.00)
    selectorWrapper2.Apply(selectorWrapper1.Apply(source)).WriteLine(); // (c, 1.00)
    // Homomorphism: selector.Wrap().Apply(value.Wrap()) == selector(value).Wrap().
    selector.ValueTuple<string, Func<int, double>>().Apply(value.ValueTuple<string, int>()).WriteLine(); // (, 2.23606797749979)
    selector(value).ValueTuple<string, double>().WriteLine(); // (, 2.23606797749979)
    // Interchange: selectorWrapper.Apply(value.Wrap()) == (selector => selector(value)).Wrap().Apply(selectorWrapper).
    selectorWrapper1.Apply(value.ValueTuple<string, int>()).WriteLine(); // (b, 2.23606797749979)
    new Func<Func<int, double>, double>(function => function(value))
        .ValueTuple<string, Func<Func<int, double>, double>>().Apply(selectorWrapper1).WriteLine(); // (, 2.23606797749979)
}

45 Comments

  • سکوبندی آزمایشگاه

  • A pedido de amigos os resultados anteriores foram incluídos nesta página.
    Deu no poste.
    Segunda-Feira 2020 O resultado do jogo do bicho,
    deu no poste desta Domingo,
    segue abaixo para apuração.
    Pesquise sempre por
    “jogo do bicho portalbrasil.

  • Amazon.com/mytv - enter the 6 digit amazon mytv code you receive at screen at www.amazon.com/mytv to regiter your device. contact amazon support for hel

  • good post

  • This article is really fantastic and thanks for sharing the valuable post.

  • awesome post. I’m a normal visitor of your web site and appreciate you taking the time to maintain the nice site. I’ll be a frequent visitor for a long time.

  • Thanks for sharing.I found a lot of interesting information here. A really good post, very thankful and hopeful that you will write many more

  • Great Article it its really informative and innovative keep us posted with new updates. its was really valuable. 

  • Thanks for writing such a good article, I stumbled onto your blog and read a few post. I like your style of writing...

  • Great Post !! Very interesting topic will bookmark your site to check if you write more about in the future.

  • Very interesting topic will bookmark your site to check if you Post more about in the future.

  • Thanks for share amazing content. Very interesting keep posting.

  • کلینیک لیزر شفا به عنوان بهترین مرکز درمان بیماری های گوارشی و نشیمن گاهی با مدیریت دکتر داود تاج بخش در رابطه با بیماریهای ناحیه مقعد خدماتی از جمله درمان بیماری هایی مثل هموروئید، فیستول، شقاق ارائه می دهد. کلینیک لیزر شفا فقط و فقط بر روی بیماری های مقعدی تمرکز داشته و تمامی متخصصین در این رابطه دور هم گرد آورده است.
    https://laser-doc.com/

  • Walmart Giftcard Balance | Check Walmart Gift Card Balance is actively using the technology Domain Not Resolving for its website, according to BuiltWith.

  • Very attractive blog with amazing informations.

  • This post is really astounding one! I was delighted to read this, very much useful. Many thanks

  • Hey! Someone in my Myspace group shared this website with us so I came to look it over.
    I'm definitely loving the information. I'm book-marking and will be
    tweeting this to my followers! Exceptional blog and great
    style and design.

  • Great looking web site. Assume you did a lot of your very own html coding.

  • Hi there, just wanted to tell you, I liked this article. It was inspiring.
    Keep on posting!

  • Great internet site! It looks very expert! Keep up the
    good work!

  • OMG this game deserves to be played by the whole world.

  • I got such a useful stuff on your website that helps me a lot to gain information.

  • Very nice post. Every day from distinct blogs, I learn something different.

  • Thank you so much for sharing your thoughts. This is exactly what I needs.

  • I am very glad that I am one of the visitors of this great website.

  • Daily I visit most of the web pages to get new stuff. But here I got something unique and informative.

  • Very energetic post! Everyone is searching for the wonderful stuff.

  • I am very glad that I am one of the visitors of this great website.

  • Daily I visit most of the web pages to get new stuff. But here I got something unique and informative.

  • This is the one of the most important information for me. And I am feeling glad reading your article. The article is really excellent ?

  • It helps to get more knowledge about this topic. I really appreciate your effort that you put to provide such great article.

  • Your website always shares such an useful information that I was looking for.

  • Thank you so much for sharing your thoughts. This is exactly what I needs.

  • Your website contains such useful information. Appreciate your written skills and your blog.

  • This formula that you for all intents and purposes are presenting seems rigid to me, since basically your previous research essentially was definitely promising to me.

  • https://ma-study.blogspot.com/

  • If you are writing your dissertation, thesis report, or any other paper and don't know what material to put into it? visit Dissertation Writing Help & get the best assistance from our expert writers on board.

  • Friday Night Funkin is a game created by ninja_muffin99 and some others. This game is brought to life by the music contained in this game. It has simple gameplay but very difficult to win.

  • KBH games is a game website with the highest quality and fastest speed today. It meets many of the standards you need, Here we are constantly updating many new games that you should try it now.

  • following caused error anyone help!
    public static partial class TaskExtensions // Task<T> : IMonoidalFunctor<Task<>>
    {
    // Multiply: Task<T1> x Task<T2> -> Task<T1 x T2>
    // Multiply: (Task<T1>, Task<T2>) -> Task<(T1, T2)>

  • برخی از بازی های  شرکت بلیزارد بصورت رایگان دردسترس گیمرها و کاربران نخواهد بود. و این کاربران برای استفاده از بازی  گیم تایم یا همان گیم کارت خریداری کنند. یکی از این بازی ها،‌ بازی محبوب و پرطرفدار ورلدآف وارکرافت است. به شارژ ماهیانه بازی وارکرافت در سرورهای بازی بلیزارد  گیم تایم می گویند ، که در فروشگاه جت گیم موجود می باشد.

    خرید گیم تایم 60 روزه ازفروشگاه جت گیم:

    در واقع گیم تایم 60 روزه نمونه ای جدید است از گیم تایم ها برای استفاده دربازی World of Warcraft  . که در ادامه بیشتر در مورد این محصول و نحوه استفاده از آن توضیح می دهیم .

    شما با خرید گیم تایم 60 روزه در مدت زمان آن گیم تایم ( 60 روز ) به امکاناتی در بازی World of Warcraft درسترسی پیدا خواهید کرد که این امکانات شامل موارد زیر میباشند :

    1 - اجازه لول آپ کردن تا لول 50 ( بدون گیم تایم فقط می توانید تا لول 20 بازی کنید )

    2 - اجازه  چت کردن با دیگران درون بازی ( بدون گیم تایم نمی توانید در بازی  چت کنید )

    3 - دسترسی به بازی World of Warcraft Classic

    در نتیجه برای بازی در World of Warcraft حتمآ به تهیه گیم تایم نیاز دارید.

    نکته 1 : گیم تایم یا همان زمان بازی ورد اف وارکرفت برای توانایی انلاین بازی کردن استفاده می شود و بدون گیم تایم امکان بازی کردن بازی محبوب ورد اف وارکرفت را نخواهید داشت.

    نکته 2 : درصورتی که گیم تایم نداشته باشید امکان بازی ورد اف وارکرفت کلاسیک را ندارید و شما میتوانید جهت خرید این محصول از وبسایت ما اقدام نمایید

    نکته 3 : نیازی به وارد کردن مشخصات اکانت بلیزارد شما نمی باشد زیرا کد گیم تایم  توسط خود شما و پس از دریافت کد، وارد می شود  ( آموزش وارد کردن در پایین صفحه قرار دارد )

  • برخی از بازی های  شرکت بلیزارد بصورت رایگان دردسترس گیمرها و کاربران نخواهد بود. و این کاربران برای استفاده از بازی  گیم تایم یا همان گیم کارت خریداری کنند. یکی از این بازی ها،‌ بازی محبوب و پرطرفدار ورلدآف وارکرافت است. به شارژ ماهیانه بازی وارکرافت در سرورهای بازی بلیزارد  گیم تایم می گویند ، که در فروشگاه جت گیم موجود می باشد.

    خرید گیم تایم 60 روزه ازفروشگاه جت گیم:

    در واقع گیم تایم 60 روزه نمونه ای جدید است از گیم تایم ها برای استفاده دربازی World of Warcraft  . که در ادامه بیشتر در مورد این محصول و نحوه استفاده از آن توضیح می دهیم .

    شما با خرید گیم تایم 60 روزه در مدت زمان آن گیم تایم ( 60 روز ) به امکاناتی در بازی World of Warcraft درسترسی پیدا خواهید کرد که این امکانات شامل موارد زیر میباشند :

    1 - اجازه لول آپ کردن تا لول 50 ( بدون گیم تایم فقط می توانید تا لول 20 بازی کنید )

    2 - اجازه  چت کردن با دیگران درون بازی ( بدون گیم تایم نمی توانید در بازی  چت کنید )

    3 - دسترسی به بازی World of Warcraft Classic

    در نتیجه برای بازی در World of Warcraft حتمآ به تهیه گیم تایم نیاز دارید.

    نکته 1 : گیم تایم یا همان زمان بازی ورد اف وارکرفت برای توانایی انلاین بازی کردن استفاده می شود و بدون گیم تایم امکان بازی کردن بازی محبوب ورد اف وارکرفت را نخواهید داشت.

    نکته 2 : درصورتی که گیم تایم نداشته باشید امکان بازی ورد اف وارکرفت کلاسیک را ندارید و شما میتوانید جهت خرید این محصول از وبسایت ما فروشگاه جت گیم اقدام نمایید

  • Very good content. I appreciate your writing skills.

  • <a href="https://pg-slot.game/%e0%b8%9a%e0%b8%a3%e0%b8%b4%e0%b8%81%e0%b8%b2%e0%b8%a3/pgslot/%e0%b9%82%e0%b8%9a%e0%b8%99%e0%b8%b1%e0%b8%aa-pgslot-%e0%b9%84%e0%b8%94%e0%b9%89%e0%b9%80%e0%b8%87%e0%b8%b4%e0%b8%99%e0%b8%a1%e0%b8%b2%e0%b8%81%e0%b8%81%e0%b8%a7%e0%b9%88%e0%b8%b2%e0%b8%96%e0%b8%b9%e0%b8%81-%e0%b8%ab%e0%b8%a7%e0%b8%a2/">โบนัส Pgslot ได้เงินมากกว่าถูก หวย</a> เล่นเกม Pgslot มีให้ลุ้นทุกวันทุกเวลาไม่ต้องรอเหมือนหวย Pgslot มีเกมภาพสวยๆมากมาย นักเสี่ยงโชคไม่ควรพลาด  

  • veru good
    thank you so much

Add a Comment

As it will appear on the website

Not displayed

Your website