Pourquoi les foncteurs Haskell ont-ils uniquement des types dérivés dans leur catégorie cible?

12

Dans Haskell, le foncteur de classe de types Functor est défini comme suit (voir par exemple le wiki Haskell ):

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

Pour autant que je comprends (s'il vous plaît me corriger si je me trompe), un tel foncteur ne peut avoir que la catégorie cible une catégorie construite en utilisant un constructeur de type, par exemple [], Maybeetc. D'autre part, on peut penser à foncteurs ayant une catégorie comme cible d'un foncteur, par exemple la catégorie de tous les types Haskell. Par exemple, Intpourrait être un objet dans la catégorie cible d'un foncteur, pas seulement Maybe Intou [Int].

Quelle est la motivation de cette restriction sur les foncteurs Haskell?

Giorgio
la source
4
Simplicité? Haskell n'a pas de fonctions de type de première classe, donc toutes les fonctions ne sont vraiment que des constructeurs de types.
Daniel Gratzer
2
@jozefg: Pardonnez mon ignorance: que sont les "fonctions de type de première classe"?
Giorgio
4
Donc, dans cette fonction, nous tournons autour d'un fdroit? Et dans votre scénario, fdevrait être comme une fonction Haskell normale et mapper des types à des types. Dans Haskell, les seuls éléments autorisés à avoir le type * -> *sont les constructeurs de type. Les familles de types sont plus générales, mais elles doivent toujours être pleinement appliquées
Daniel Gratzer
Cette question est liée.
Ptharien's Flame
@jozefg: Je pense de temps en temps à cette question encore et encore. Je suppose que la restriction Haskell n'affecte pas le pouvoir expressif des foncteurs. Par exemple, supposons que nous ayons un foncteur qui est isomorphe au foncteur de liste, mais qui ne mappe pas, disons, Int -> [Int] mais Int -> <type fantaisie sans constructeur de type>. Ensuite, je suppose que l'on pourrait prouver que <type fantaisie sans constructeur de type> est isomorphe à [Int]. Donc, choisir des objets définis à l'aide d'un constructeur de type est juste pratique et ne sacrifie pas le pouvoir expressif.
Giorgio

Réponses:

1

Il n'y a aucune restriction! Lorsque j'ai commencé à apprendre les bases théoriques des catégories pour les constructeurs de types, ce point m'a également troublé. Nous y reviendrons. Mais d'abord, permettez-moi de dissiper une certaine confusion. Ces deux citations:

un tel foncteur ne peut avoir comme catégorie cible qu'une catégorie construite à l'aide d'un constructeur de type

et

on peut penser à des foncteurs ayant n'importe quelle catégorie comme cible d'un foncteur, par exemple la catégorie de tous les types Haskell

montrez que vous comprenez mal ce qu'est un foncteur (ou, à tout le moins, que vous utilisez mal la terminologie).

Les foncteurs ne construisent pas de catégories. Un foncteur est un mappage entre les catégories. Les foncteurs apportent des objets et des morphismes (types et fonctions) dans la catégorie source à des objets et des morphismes dans la catégorie cible.

Notez que cela signifie qu'un foncteur est en réalité une paire de mappages: un mappage sur les objets F_obj et un mappage sur les morphismes F_morph . Dans Haskell, la partie objet F_obj du foncteur est le nom du constructeur de type (par exemple List), tandis que la partie morphisme est la fonction fmap(c'est au compilateur Haskell de trier ce à quoi fmapnous nous référons dans une expression donnée). Ainsi, nous ne pouvons pas dire que Listc'est un foncteur; seule la combinaison de Listet fmapest un foncteur. Pourtant, les gens abusent de la notation; les programmeurs appellent Listun foncteur, tandis que les théoriciens des catégories utilisent le même symbole pour faire référence aux deux parties du foncteur.

De plus, en programmation, presque tous les foncteurs sont des endofuncteurs , c'est-à-dire que la catégorie source et la cible sont les mêmes - la catégorie de tous les types dans notre langage. Appelons ce type de catégorie . Un endofoncteur F sur Type mappe un type T à un autre type FT et une fonction T -> S à une autre fonction FT -> FS . Cette cartographie doit bien entendu obéir aux lois des foncteurs.

En utilisant Listcomme exemple: nous avons un constructeur de type List : Type -> Type, et une fonction fmap: (a -> b) -> (List a -> List b), qui forment ensemble un foncteur. T

Il y a un dernier point à clarifier. L'écriture List intne crée pas un nouveau type de listes d'entiers. Ce type existait déjà . C'était un objet dans notre catégorie Type . List Intest simplement un moyen de s'y référer.

Maintenant, vous vous demandez pourquoi un foncteur ne peut pas mapper un type sur, disons, Intou String. Mais c'est possible! Il suffit d'utiliser le foncteur d'identité. Pour toute catégorie C , le foncteur identité cartes chaque objet lui - même et morphisme à lui - même. Il est simple de vérifier que ce mappage satisfait aux lois du foncteur. Dans Haskell, ce serait un constructeur de type id : * -> *qui mappe chaque type à lui-même. Par exemple, id intévalue à int.

De plus, on peut même créer des foncteurs constants , qui mappent tous les types à un seul type. Par exemple, le foncteur ToInt : * -> *, où ToInt a = intpour tous les types a, et mappe tous les morphismes à la fonction d'identité entière: fmap f = \x -> x

gardenhead
la source
Merci pour votre réponse, cette question a plus de deux ans. "Les foncteurs ne construisent pas de catégories.": Je n'ai pas dit ça. J'ai dit que les foncteurs mappent deux catégories, où la catégorie cible doit avoir la forme f a, où fest, pour autant que je sache, un constructeur de type. D'après ce dont je me souviens de la théorie des catégories, cela doit être une sorte de représentation canonique (objet initial dans une catégorie de catégories? Peut-être que j'utilise mal la terminologie.) Quoi qu'il en soit, je vais lire attentivement votre réponse. Merci beaucoup.
Giorgio
@Giorgio whoops, je n'ai pas remarqué son âge haha. Il est juste apparu dans les "questions sans réponse". Je ne sais pas ce que vous entendez par "représentation canonique". Pour autant que je sache (et je peux me tromper ici), il n'y a pas de relation entre les foncteurs et les objets initiaux / terminaux.
gardenhead
Je veux dire ceci: en.wikipedia.org/wiki/Initial_algebra (voir Utilisation en informatique). Dans Haskell (la plupart), les foncteurs sont définis sur des types de données algébriques. L'objet cible d'un tel foncteur est une algèbre initiale. L'algèbre initiale est isomorphe à l'ensemble des termes construits à l'aide des constructeurs de valeurs. Par exemple, pour les listes, []et :. Je voulais dire cela par représentation canonique.
Giorgio
Oui, je sais ce qu'est un objet initial et que les types de données inductifs sont des objets initiaux dans l'algèbre F d'une catégorie. Vous avez raison de dire que de nombreux constructeurs de types sont définis de manière inductive. Mais ce n'est pas strictement nécessaire. Par exemple, le foncteur (_, int)qui prend un type aau type de produit (a, int)et une fonction f : 'a -> 'bà g : 'a * int -> 'a * intn'est pas inductif.
gardenhead
Vouliez-vous dire: "prend ... une fonction f : 'a -> 'bpour g : 'a * int -> 'b * int?
Giorgio