Es gibt überhaupt keine Einschränkung! Als ich anfing, die kategorietheoretischen Grundlagen für Typkonstruktoren zu lernen, verwirrte mich genau dieser Punkt ebenfalls. Wir werden darauf kommen. Aber lassen Sie mich zuerst ein wenig Verwirrung stiften. Diese zwei Anführungszeichen:
Ein solcher Funktor kann nur eine Kategorie als Zielkategorie haben, die mit einem Typkonstruktor erstellt wurde
und
Man kann sich Funktoren mit einer beliebigen Kategorie als Ziel eines Funktors vorstellen, z. B. die Kategorie aller Haskell-Typen
Zeigen Sie, dass Sie falsch verstehen, was ein Funktor ist (oder zumindest, dass Sie Terminologie falsch verwenden).
Functors nicht konstruieren Kategorien. Ein Funktor ist eine Zuordnung zwischen Kategorien. Funktoren bringen Objekte und Morphismen (Typen und Funktionen) in der Quellkategorie zu Objekten und Morphismen in der Zielkategorie.
Beachten Sie, dass dies bedeutet, dass ein Funktor tatsächlich ein Paar von Zuordnungen ist: eine Zuordnung zu Objekten F_obj und eine Zuordnung zu Morphismen F_morph . In Haskell ist der Objektteil F_obj des Funktors der Name des Typkonstruktors (z. B. List
), während der Morphism-Teil die Funktion ist fmap
(es ist Sache des Haskell-Compilers, die zu sortieren, auf die fmap
wir in einem gegebenen Ausdruck verweisen). Wir können also nicht sagen, dass dies List
ein Funktor ist; nur die kombination von List
und fmap
ist ein funktor. Trotzdem missbrauchen die Leute die Notation; Programmierer rufen List
einen Funktor auf, während Kategorietheoretiker dasselbe Symbol verwenden, um auf beide Teile des Funktors zu verweisen.
Darüber hinaus sind in der Programmierung fast alle Funktoren Endofunktionen , dh die Quell- und Zielkategorie sind identisch - die Kategorie aller Typen in unserer Sprache. Nennen wir diese Kategorie Typ . Ein Endofunctor F on Type ordnet einen Typ T einem anderen Typ FT und eine Funktion T -> S einer anderen Funktion FT -> FS zu . Dieses Mapping muss natürlich den functor-Gesetzen entsprechen.
Unter Verwendung List
als Beispiel: Wir haben einen Typkonstruktor List : Type -> Type
, und eine Funktion fmap: (a -> b) -> (List a -> List b)
, die zusammen einen Funktor bilden. T
Es gibt noch einen letzten Punkt, der geklärt werden muss. Schreiben List int
nicht schaffen , eine neue Art von Listen von ganzen Zahlen. Dieser Typ existierte bereits . Es war ein Objekt in unserer Kategorie Typ . List Int
ist einfach ein Weg, sich darauf zu beziehen.
Nun fragen Sie sich, warum ein Funktor keinen Typ, sagen wir abbilden kann, Int
oder String
. Aber es kann! Man muss nur den Identity-Funktor benutzen. Für jede Kategorie C ordnet der Identitätsfunktor jedes Objekt sich selbst und den Morphismus sich selbst zu. Es ist unkompliziert zu überprüfen, ob diese Zuordnung den Funktionsgesetzen entspricht. In Haskell wäre dies ein Typkonstruktor id : * -> *
, der jeden Typ auf sich selbst abbildet. Wertet zum Beispiel id int
zu aus int
.
Darüber hinaus kann man sogar konstante Funktoren erstellen , die alle Typen einem einzigen Typ zuordnen. Zum Beispiel der Funktor ToInt : * -> *
, in dem ToInt a = int
für alle Typen a
und alle Morphismen der ganzzahligen Identitätsfunktion zugeordnet sind: fmap f = \x -> x