Warum haben Haskell-Funktoren nur abgeleitete Typen in ihrer Zielkategorie?

12

In Haskell ist der Functor-Typenklassen-Functor wie folgt definiert (siehe zB Haskell-Wiki ):

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

Soweit ich (bitte korrigieren Sie mich , wenn ich falsch bin) zu verstehen, wie ein Funktor nur als Zielkategorie eine Kategorie eines Typkonstruktor aufgebaut haben kann, zB [], Maybeusw. Auf der anderen Seite kann man von functors denkt jede Kategorie mit als Ziel eines Funktors, zB die Kategorie aller Haskell-Typen. Dies Intkönnte beispielsweise ein Objekt in der Zielkategorie eines Funktors sein, nicht nur Maybe Intoder [Int].

Was ist die Motivation für diese Einschränkung bei Haskell-Funktoren?

Giorgio
quelle
4
Einfachheit? Haskell hat keine erstklassigen Typfunktionen, daher sind alle Funktionen nur Typkonstruktoren.
Daniel Gratzer
2
@jozefg: Entschuldigen Sie meine Unwissenheit: Was sind "erstklassige Typfunktionen"?
Giorgio
4
Also werfen wir in dieser Funktion ein fRecht herum ? Und in Ihrem Szenario fsollte es genau wie eine normale Haskell-Funktion sein und Typen zu Typen zuordnen. In Haskell dürfen nur Typkonstruktoren verwendet * -> *werden. Typfamilien sind allgemeiner, aber sie müssen immer vollständig angewendet werden
Daniel Gratzer
Diese Frage ist verwandt.
Pthariens Flamme
@jozefg: Ich denke gelegentlich immer wieder über diese Frage nach. Ich nehme an, die Haskell-Einschränkung hat keinen Einfluss auf die Ausdruckskraft von Funktoren. Nehmen wir zum Beispiel an, wir haben einen Funktor, der isomorph zum Listen-Funktor ist, aber nicht beispielsweise Int -> [Int], sondern Int -> <ausgefallener Typ ohne Typkonstruktor> abbildet. Dann könnte man wohl beweisen, dass <ausgefallener Typ ohne Typkonstruktor> isomorph zu [Int] ist. Die Auswahl von Objekten, die mit einem Typkonstruktor definiert wurden, ist also einfach bequem und beeinträchtigt nicht die Ausdruckskraft.
Giorgio

Antworten:

1

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 fmapwir in einem gegebenen Ausdruck verweisen). Wir können also nicht sagen, dass dies Listein Funktor ist; nur die kombination von Listund fmapist ein funktor. Trotzdem missbrauchen die Leute die Notation; Programmierer rufen Listeinen 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 Listals 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 intnicht schaffen , eine neue Art von Listen von ganzen Zahlen. Dieser Typ existierte bereits . Es war ein Objekt in unserer Kategorie Typ . List Intist einfach ein Weg, sich darauf zu beziehen.

Nun fragen Sie sich, warum ein Funktor keinen Typ, sagen wir abbilden kann, Intoder 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 intzu 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 = intfür alle Typen aund alle Morphismen der ganzzahligen Identitätsfunktion zugeordnet sind: fmap f = \x -> x

Gartenkopf
quelle
Vielen Dank für Ihre Antwort, diese Frage ist über zwei Jahre alt. "Functors konstruieren keine Kategorien.": Das habe ich nicht gesagt. Ich sagte, dass Funktoren zwei Kategorien zuordnen, wobei die Zielkategorie die Form haben muss f a, wobei fes sich meines Wissens um einen Typkonstruktor handelt. Soweit ich mich aus der Kategorietheorie erinnere, muss dies eine Art kanonische Repräsentation sein (ursprüngliches Objekt in einer Kategorie von Kategorien? Vielleicht verwende ich die Terminologie falsch.) Wie auch immer, ich werde Ihre Antwort sorgfältig lesen. Danke vielmals.
Giorgio
@ Giorgio whoops, ich habe nicht bemerkt, wie alt es war haha. Es zeigte sich nur in "unbeantworteten Fragen". Ich bin mir nicht sicher, was Sie unter "kanonischer Darstellung" verstehen. Soweit ich weiß (und ich könnte mich hier irren), gibt es keine Beziehung zwischen Funktoren und Anfangs- / Endobjekten.
Gardenhead
Ich meine dies: en.wikipedia.org/wiki/Initial_algebra (siehe Verwendung in der Informatik). In Haskell werden (die meisten) Funktoren für einen algebraischen Datentyp definiert. Das Zielobjekt eines solchen Funktors ist eine Anfangsalgebra. Die anfängliche Algebra ist isomorph zu der Menge von Begriffen, die mit den Wertekonstruktoren erstellt wurden. ZB für Listen []und :. Ich meinte das mit kanonischer Darstellung.
Giorgio
Ja, ich weiß, was ein Anfangsobjekt ist und dass induktive Datentypen Anfangsobjekte in der F-Algebra einer Kategorie sind. Sie haben Recht, dass viele Typkonstruktoren induktiv definiert sind. Dies ist aber nicht zwingend erforderlich. Beispielsweise ist der Funktor (_, int), der einen Typ azu dem Produkttyp (a, int)und eine Funktion f : 'a -> 'bzu g : 'a * int -> 'a * intnimmt, nicht induktiv.
Gardenhead
Meinten Sie: "nimmt ... eine Funktion f : 'a -> 'bauf g : 'a * int -> 'b * int?
Giorgio