Teoría de categorías a través de C# (4) Transformación natural

Teoría de categorías a través de C# (4) Transformación natural

[LINQ a través de la serie C#]

[Teoría de categorías a través de la serie C#]

Transformación natural y naturalidad

Si F:C → D y G:C → D son ambos funtores de las categorías C a la categoría D, el mapeo de F a G se llama transformación natural y se denota como α:F ⇒ G. α:F ⇒ G es en realidad una familia de morfismos de F a G, para cada objeto X en la categoría C, hay un morfismo específico αX :F(X) → G(X) en la categoría D, llamada componente de α en X. Para cada morfismo m:X → Y en la categoría C y 2 funtores F:C → D, G:C → D, hay un cuadrado de naturalidad en D:

En otras palabras, para m:X → Y en la categoría C, debe haber αY ∘ F(m) ≡ G(m) ∘ αX , o equivalentemente αY ∘ SeleccioneF (m) ≡ SeleccionarG (m) ∘ αX en la categoría D.

En la categoría DotNet, el siguiente método genérico ToLazy<> transforma el funtor Func<> en el funtor Lazy<>:

public static partial class NaturalTransformations
{
    // ToLazy: Func<> -> Lazy<>
    public static Lazy<T> ToLazy<T>(this Func<T> function) => new Lazy<T>(function);
}

Aparentemente, para la transformación natural anterior:ToLazy<>:Func<> ⇒ Lazy<>:

  • para cada objeto T específico, hay un objeto Func, un objeto Lazy y un morfismo ToFunc:Func → Lazy.
  • Para cada selector de morfismos específico:TSource → TResult, hay un cuadrado de naturalidad, que consta de 4 morfismos:
    • ToLazy:Func → Lazy, que es el componente de ToLazy<> en TResult
    • FuncExtensions.Select(selector):Func → Func
    • LazyExtensions.Select(selector):Lazy → Lazy
    • ToLazy:Func → Lazy, que es el componente de ToLazy<> en TSource

El siguiente ejemplo es un cuadrado de naturalidad simple que conmuta para ToLazy<>:

internal static void Naturality()
{
    Func<int, string> selector = int32 => Math.Sqrt(int32).ToString("0.00");

    // Naturality square:
    // ToFunc<string>.o(LazyExtensions.Select(selector)) == FuncExtensions.Select(selector).o(ToFunc<int>)
    Func<Func<string>, Lazy<string>> funcStringToLazyString = ToLazy<string>;
    Func<Func<int>, Func<string>> funcInt32ToFuncString = FuncExtensions.Select(selector);
    Func<Func<int>, Lazy<string>> leftComposition = funcStringToLazyString.o(funcInt32ToFuncString);
    Func<Lazy<int>, Lazy<string>> lazyInt32ToLazyString = LazyExtensions.Select(selector);
    Func<Func<int>, Lazy<int>> funcInt32ToLazyInt32 = ToLazy<int>;
    Func<Func<int>, Lazy<string>> rightComposition = lazyInt32ToLazyString.o(funcInt32ToLazyInt32);

    Func<int> funcInt32 = () => 2;
    Lazy<string> lazyString = leftComposition(funcInt32);
    lazyString.Value.WriteLine(); // 1.41
    lazyString = rightComposition(funcInt32);
    lazyString.Value.WriteLine(); // 1.41
}

Y los siguientes son algunos ejemplos más de transformaciones naturales:

// ToFunc: Lazy<T> -> Func<T>
public static Func<T> ToFunc<T>(this Lazy<T> lazy) => () => lazy.Value;

// ToEnumerable: Func<T> -> IEnumerable<T>
public static IEnumerable<T> ToEnumerable<T>(this Func<T> function)
{
    yield return function();
}

// ToEnumerable: Lazy<T> -> IEnumerable<T>
public static IEnumerable<T> ToEnumerable<T>(this Lazy<T> lazy)
{
    yield return lazy.Value;
}

Categoría de funtores

Ahora hay funtores y mapeos entre funtores, que son transformaciones naturales. Naturalmente, conducen a la categoría de funtores. Dadas 2 categorías C y D, existe una categoría de funtores, denominada D C :

  • Sus objetos ob(D C ) son los funtores de la categoría C a D .
  • Sus morfismos hom(D C ) son las transformaciones naturales entre esos funtores.
  • La composición de las transformaciones naturales α:F ⇒ G y β:G ⇒ H, es transformaciones naturales (β ∘ α):F ⇒ H.
  • La transformación natural de la identidad idF :F ⇒ F asigna cada funtor a sí mismo

En cuanto a la categoría leyes:

  • Ley de asociatividad:como se mencionó anteriormente, los componentes de la transformación natural son morfismos en D, por lo que la composición de la transformación natural en D C puede verse como una composición de morfismos en D:(β ∘ α)X :F(X) → H(X) =(βX :G(X) → H(X)) ∘ (αX :F(X) → G(X)). Composición de transformaciones naturales en D C es asociativa, ya que la composición de todos los morfismos componentes en D es asociativa
  • Ley de identidad:de manera similar, los componentes de la transformación natural de identidad son los morfismos id idF(X) :F(X) → F(X) en D. La transformación natural de identidad satisface la ley de identidad, ya que todos sus componentes satisfacen la ley de identidad.

Aquí hay un ejemplo de composición de transformaciones naturales:

// ToFunc: Lazy<T> -> Func<T>
public static Func<T> ToFunc<T>(this Lazy<T> lazy) => () => lazy.Value;
#endif

// ToOptional: Func<T> -> Optional<T>
public static Optional<T> ToOptional<T>(this Func<T> function) =>
    new Optional<T>(() => (true, function()));

// ToOptional: Lazy<T> -> Optional<T>
public static Optional<T> ToOptional<T>(this Lazy<T> lazy) =>
    // new Func<Func<T>, Optional<T>>(ToOptional).o(new Func<Lazy<T>, Func<T>>(ToFunc))(lazy);
    lazy.ToFunc().ToOptional();
}

Categoría de endofunción

Dada la categoría C, existe una categoría de endofuntores, denominada C C , o End(C), donde los objetos son los endofuntores de la categoría C a C misma, y ​​los morfismos son las transformaciones naturales entre esos endofuntores.

Todos los funtores en C# son endofuntores de la categoría DotNet a DotNet. Son los objetos de la categoría endofunctor DotNet DotNet o Fin (DotNet).