Não há nenhuma restrição! Quando comecei a aprender a base teórica da categoria para construtores de tipos, esse mesmo ponto também me confundiu. Nós vamos chegar a isso. Mas primeiro, deixe-me esclarecer alguma confusão. Estas duas citações:
esse functor pode ter apenas como categoria de destino uma categoria construída usando um construtor de tipo
e
pode-se pensar em functores tendo qualquer categoria como alvo de um functor, por exemplo, a categoria de todos os tipos de Haskell
mostre que você está entendendo mal o que é um functor (ou pelo menos está usando mal a terminologia).
Functors não constroem categorias. Um functor é um mapeamento entre categorias. Os fundores trazem objetos e morfismos (tipos e funções) na categoria de origem para objetos e morfismos na categoria de destino.
Observe que isso significa que um functor é realmente um par de mapeamentos: um mapeamento nos objetos F_obj e um mapeamento nos morfismos F_morph . Em Haskell, a parte do objeto F_obj do functor é o nome do construtor de tipos (por exemplo List
), enquanto a parte do morfismo é a função fmap
(cabe ao compilador Haskell classificar a que fmap
estamos nos referindo em qualquer expressão). Assim, não podemos dizer que List
é um functor; apenas a combinação de List
e fmap
é um functor. Ainda assim, as pessoas abusam da notação; os programadores chamam List
um functor, enquanto os teóricos da categoria usam o mesmo símbolo para se referir às duas partes do functor.
Além disso, na programação, quase todos os functores são endofuncionadores , ou seja, a categoria de origem e destino são os mesmos - a categoria de todos os tipos em nossa linguagem. Vamos chamar essa categoria de Tipo . Um endofuncor F no tipo mapeia um tipo T para outro tipo FT e uma função T -> S para outra função FT -> FS . É claro que esse mapeamento deve obedecer às leis do functor.
Usando List
como exemplo: temos um construtor de tipos List : Type -> Type
e uma função fmap: (a -> b) -> (List a -> List b)
que juntos formam um functor. T
Há um último ponto a esclarecer. A escrita List int
não cria um novo tipo de lista de números inteiros. Este tipo já existia . Foi um objeto em nossa categoria Tipo . List Int
é simplesmente uma maneira de se referir a ele.
Agora, você está se perguntando por que um functor não pode mapear um tipo para, digamos, Int
ou String
. Mas pode! Basta usar o functor de identidade. Para qualquer categoria C , o functor de identidade mapeia todos os objetos para si e o morfismo para si. É fácil verificar se esse mapeamento satisfaz as leis do functor. Em Haskell, esse seria um construtor de tipos id : * -> *
que mapeia todos os tipos para si. Por exemplo, id int
avalia como int
.
Além disso, pode-se até criar functores constantes , que mapeiam todos os tipos para um único tipo. Por exemplo, o functor ToInt : * -> *
, onde ToInt a = int
para todos os tipos a
, e mapeia todos os morfismos para a função de identidade inteira: fmap f = \x -> x