Non ci sono restrizioni! Quando ho iniziato a studiare le basi teoriche di categoria per i costruttori di tipi, anche questo punto mi ha confuso. Ci arriveremo. Ma prima lasciami chiarire un po 'di confusione. Queste due citazioni:
tale funzione può avere solo come categoria target una categoria costruita usando un costruttore di tipi
e
si può pensare a funzioni aventi qualsiasi categoria come bersaglio di un funzione, ad esempio la categoria di tutti i tipi di Haskell
mostra che stai fraintendendo cosa sia un funzione (o per lo meno stai abusando della terminologia).
I portatori non costruiscono categorie. Un funzione è una mappatura tra le categorie. I portatori portano oggetti e morfismi (tipi e funzioni) nella categoria sorgente all'oggetto e morfismi nella categoria obiettivo.
Si noti che ciò significa che un funzione è in realtà una coppia di mappature: una mappatura su oggetti F_obj e una mappatura su morfismi F_morph . In Haskell, la parte oggetto F_obj del functor è il nome del tipo costruttore (ad es. List), Mentre la parte morfismo è la funzione fmap(spetta al compilatore Haskell per risolvere il problema a cui fmapci riferiamo in una determinata espressione). Pertanto, non possiamo dire che Listsia un funzione; solo la combinazione di Listed fmapè un funzione. Tuttavia, la gente abusa della notazione; i programmatori chiamano Listun funzione, mentre i teorici di categoria usano lo stesso simbolo per riferirsi ad entrambe le parti del funzione.
Inoltre, nella programmazione, quasi tutti i funzioni sono endofunctor , ovvero la categoria sorgente e destinazione sono le stesse - la categoria di tutti i tipi nella nostra lingua. Chiamiamo questa categoria Tipo . Un endofunctor F su Type mappa un tipo T su un altro tipo FT e una funzione T -> S su un'altra funzione FT -> FS . Questa mappatura deve ovviamente obbedire alle leggi dei funzioni.
Usando Listcome esempio: abbiamo un costruttore di tipi List : Type -> Typee una funzione fmap: (a -> b) -> (List a -> List b)che insieme formano un funzione. T
C'è un ultimo punto da chiarire. La scrittura List intnon crea un nuovo tipo di elenchi di numeri interi. Questo tipo esisteva già . Era un oggetto nella nostra categoria Tipo . List Intè semplicemente un modo per fare riferimento ad esso.
Ora ti stai chiedendo perché un functor non può mappare un tipo su, diciamo, Into String. Ma può! Basta usare il identificatore. Per ogni categoria C , il funzione identità identifica ogni oggetto su se stesso e il morfismo su se stesso. È semplice verificare che questa mappatura soddisfi le leggi dei funzioni. In Haskell, questo sarebbe un costruttore di tipi id : * -> *che mappa ogni tipo su se stesso. Ad esempio, id intvaluta int.
Inoltre, si possono persino creare costanti funzioni, che mappano tutti i tipi su un singolo tipo. Ad esempio, il functor ToInt : * -> *, dove ToInt a = intper tutti i tipi a, e associa tutti i morfismi alla funzione di identità intera: fmap f = \x -> x