¡No hay restricción alguna! Cuando comencé a aprender la base teórica de categoría para los constructores de tipos, este mismo punto también me confundió. Llegaremos a eso. Pero primero, déjame aclarar algo de confusión. Estas dos citas:
dicho functor solo puede tener como categoría objetivo una categoría construida utilizando un constructor de tipos
y
uno puede pensar en los functores que tienen cualquier categoría como objetivo de un functor, por ejemplo, la categoría de todos los tipos de Haskell
Demuestre que está malinterpretando qué es un functor (o al menos, está haciendo un mal uso de la terminología).
Los functores no construyen categorías. Un functor es un mapeo entre categorías. Los functores traen objetos y morfismos (tipos y funciones) en la categoría de origen a objetos y morfismos en la categoría de destino.
Tenga en cuenta que esto significa que un functor es realmente un par de asignaciones: una asignación en objetos F_obj y una asignación en morfismos F_morph . En Haskell, la parte del objeto F_obj del functor es el nombre del constructor de tipos (p List. Ej. ), Mientras que la parte del morfismo es la función fmap(depende del compilador de Haskell para resolver a qué fmapnos referimos en cualquier expresión dada). Por lo tanto, no podemos decir que Listes un functor; solo la combinación de Listy fmapes un functor. Aún así, las personas abusan de la notación; los programadores llaman a Listun functor, mientras que los teóricos de categoría usan el mismo símbolo para referirse a ambas partes del functor.
Además, en la programación, casi todos los functores son endofunctores , es decir, la categoría de origen y la de destino son las mismas: la categoría de todos los tipos en nuestro idioma. Llamemos a esta categoría Tipo . Un endofunctor F en Tipo asigna un tipo T a otro tipo FT y una función T -> S a otra función FT -> FS . Este mapeo debe, por supuesto, obedecer las leyes de los functores.
Usando Listcomo ejemplo: tenemos un constructor de tipos List : Type -> Typey una función fmap: (a -> b) -> (List a -> List b), que juntos forman un functor. T
Hay un último punto para aclarar. Escribir List intno crea un nuevo tipo de listas de enteros. Este tipo ya existía . Fue un objeto en nuestra categoría Tipo . List Intes simplemente una forma de referirse a él.
Ahora, se pregunta por qué un functor no puede asignar un tipo a, digamos, Into String. ¡Pero puede! Uno solo tiene que usar el functor de identidad. Para cualquier categoría C , el functor de identidad asigna cada objeto a sí mismo y el morfismo a sí mismo. Es sencillo verificar que este mapeo cumpla con las leyes de functor. En Haskell, este sería un constructor de tipos id : * -> *que asigna cada tipo a sí mismo. Por ejemplo, id intevalúa a int.
Además, incluso se pueden crear functores constantes , que asignan todos los tipos a un solo tipo. Por ejemplo, el functor ToInt : * -> *, donde ToInt a = intpara todos los tipos a, y asigna todos los morfismos a la función de identidad entera: fmap f = \x -> x