¿Por qué los funk Haskell solo tienen tipos derivados en su categoría objetivo?

12

En Haskell, el functor de la clase de tipo Functor se define de la siguiente manera (véase, por ejemplo, la wiki de Haskell ):

class Functor (f :: * -> *) where
  fmap :: (a -> b) -> f a -> f b 

Por lo que yo entiendo (por favor, corríjanme si me equivoco), un funtor tal sólo puede tener como categoría objetivo una categoría construida utilizando un constructor de tipos, por ejemplo [], Maybe, etc. Por otro lado, uno puede pensar en palabras funcionales que tengan cualquiera de las categorías como objetivo de un functor, por ejemplo, la categoría de todos los tipos de Haskell. Por ejemplo, Intpodría ser un objeto en la categoría de destino de un functor, no solo Maybe Into [Int].

¿Cuál es la motivación de esta restricción en los funk de Haskell?

Giorgio
fuente
44
¿Sencillez? Haskell no tiene funciones de tipo de primera clase, por lo que todas las funciones son realmente solo constructores de tipos.
Daniel Gratzer
2
@jozefg: Disculpe mi ignorancia: ¿qué son las "funciones de tipo de primera clase"?
Giorgio
44
Entonces, en esa función, ¿estamos dando vueltas a la fderecha? Y en su escenario, fdebe ser como una función normal de Haskell y asignar tipos a tipos. En Haskell, las únicas cosas que pueden tener el tipo * -> *son los constructores de tipos. Las familias tipográficas son más generales, pero siempre deben aplicarse por completo
Daniel Gratzer
@jozefg: ocasionalmente pienso en esta pregunta una y otra vez. Supongo que la restricción de Haskell no afecta el poder expresivo de los functores. Por ejemplo, supongamos que tenemos un functor que es isomorfo al functor de la lista, pero que no asigna, digamos, Int -> [Int] sino Int -> <tipo elegante sin utilizar ningún tipo de constructor>. Entonces supongo que se podría probar que <tipo elegante sin constructor de tipos> es isomorfo a [Int]. Por lo tanto, elegir objetos que se definen utilizando un constructor de tipo es simplemente conveniente y no sacrifica el poder expresivo.
Giorgio

Respuestas:

1

¡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

cabeza de jardín
fuente
Gracias por su respuesta, esta pregunta tiene más de dos años. "Los functores no construyen categorías": no dije eso. Dije que los functores mapean dos categorías, donde la categoría objetivo debe tener la forma f a, donde fes, hasta donde yo sé, un constructor de tipos. Por lo que recuerdo de la teoría de categorías, esto debe ser algún tipo de representación canónica (¿objeto inicial en una categoría de categorías? Tal vez estoy haciendo un mal uso de la terminología). De todos modos, leeré su respuesta cuidadosamente. Muchas gracias.
Giorgio
@Giorgio grita, no me di cuenta de la edad que tenía jaja. Simplemente apareció en "preguntas sin respuesta". No estoy seguro de lo que quieres decir con "representación canónica". Hasta donde sé (y podría estar equivocado aquí), no existe una relación entre los functores y los objetos iniciales / terminales.
cabeza de jardín
Quiero decir esto: en.wikipedia.org/wiki/Initial_algebra (ver Uso en informática). En Haskell (la mayoría) los functores se definen en tipos de datos algebraicos. El objetivo de tal functor es un álgebra inicial. El álgebra inicial es isomorfo al conjunto de términos construidos usando los constructores de valores. Por ejemplo, para listas, []y :. Quise decir esto por representación canónica.
Giorgio
Sí, sé qué es un objeto inicial, y que los tipos de datos inductivos son objetos iniciales en el álgebra F de una categoría. Tienes razón en que muchos constructores de tipos se definen inductivamente. Pero esto no es estrictamente necesario. Por ejemplo, el funtor (_, int)que toma un tipo aal tipo de producto (a, int)y una función f : 'a -> 'ba g : 'a * int -> 'a * intno es inductiva.
cabeza de jardín
¿Quería decir: "toma ... una función f : 'a -> 'bpara g : 'a * int -> 'b * int?"
Giorgio