[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).