Warum kann ich Tupel beliebiger Länge in Haskell nicht vergleichen?

7

Ich weiß, dass es vordefinierte Eq Instanzen für Tupel der Längen 2 bis 15 .

Warum werden Tupel nicht als eine Art rekursiver Datentyp definiert, so dass sie zerlegt werden können, was eine Definition einer Funktion für compare erlaubt, die mit Tupel beliebiger Länge arbeitet?

Immerhin unterstützt der Compiler Tupel beliebiger Länge.

    
Odin 04.02.2013, 10:55
quelle

4 Antworten

9

Sie könnten sich fragen, was der Typ dieser verallgemeinerten Vergleichsfunktion wäre. Zunächst müssen wir die Komponententypen verschlüsseln:

%Vor%

Es gibt wirklich nichts, was wir durch die Fragezeichen ersetzen können. Die Schlussfolgerung ist, dass eine reguläre ADT nicht ausreicht, also brauchen wir unsere erste Spracherweiterung, GADTs:

%Vor%

Aber wir enden mit Fragezeichen. Das Füllen der Löcher erfordert zwei weitere Erweiterungen, DataKinds und TypeOperators:

%Vor%

Wie Sie sehen, benötigten wir drei Typsystemerweiterungen, nur um den Typ zu codieren. Können wir jetzt vergleichen? Nun, es ist nicht so einfach zu beantworten, weil es eigentlich nicht selbstverständlich ist, eine eigenständige Vergleichsfunktion zu schreiben. Zum Glück erlaubt uns der Typklassenmechanismus einen einfachen rekursiven Ansatz. Dieses Mal wiederholen wir uns jedoch nicht nur auf der Werteebene, sondern auch auf der Typenebene. Offensichtlich sind leere Tupel immer gleich:

%Vor%

Aber der Compiler beklagt sich erneut. Warum? Wir benötigen eine andere Erweiterung, FlexibleInstances, weil '[] ein konkreter Typ ist. Jetzt können wir leere Tupel vergleichen, was nicht so zwingend ist. Was ist mit nicht leeren Tupeln? Wir müssen die Köpfe und den Rest des Tupels vergleichen:

%Vor%

Scheint Sinn zu machen, aber bumm! Wir bekommen eine weitere Beschwerde. Nun möchte der Compiler FlexibleContexte, weil wir einen nicht vollständig polymorphen Typ im Kontext Tuple as haben.

Das sind insgesamt fünf Typsystemerweiterungen, drei davon nur, um den Tupel-Typ auszudrücken, und sie existierten nicht vor GHC 7.4. Die anderen beiden werden zum Vergleich benötigt. Natürlich gibt es eine Belohnung. Wir erhalten einen sehr leistungsfähigen Tupel-Typ, aber aufgrund all dieser Erweiterungen können wir einen solchen Tupel-Typ offensichtlich nicht in die Basisbibliothek einfügen.

    
ertes 04.02.2013 15:27
quelle
8

Sie können jedes n-Tupel immer in Form von binären Tupeln umschreiben. Zum Beispiel, angesichts der folgenden 4-Tupel:

%Vor%

Sie können es wie folgt umschreiben:

%Vor%

Stellen Sie sich eine Liste vor, in der (,) die Rolle von (:) (d. h. "Nachteile") spielt und () die Rolle von [] (d. h. "Null") spielt. Mit diesem Trick können Sie, solange Sie Ihr n-Tupel in Form einer "Liste von Binär-Tupeln" formulieren, diese unbegrenzt erweitern und automatisch die richtigen Eq und Ord Instanzen ableiten.

    
Gabriel Gonzalez 04.02.2013 11:55
quelle
2

Ein Typ von compare ist a -> a -> Ordering , was darauf hindeutet, dass beide Eingaben vom selben Typ sein müssen. Tupel mit verschiedenen Artigkeiten sind per Definition verschiedene Arten.

Sie können Ihr Problem jedoch lösen, indem Sie sich entweder mit HLists oder GADTs befassen.

    
Nikita Volkov 04.02.2013 11:12
quelle
0

Ich wollte nur zur Antwort von ertes hinzufügen, dass Sie dafür keine einzige Erweiterung benötigen. Der folgende Code sollte haskell98 sowie 2010 compliant sein. Und die Datentypen darin können Tupeln einzeln zugeordnet werden, mit Ausnahme des Singleton-Tupels. Wenn Sie die Rekursion nach dem Zwei-Tupel durchführen, können Sie das auch erreichen.

%Vor%

Sie könnten auch einfach Gl. Natürlich würde es mit TypeOperators etwas kühler aussehen, aber das Listensystem von haskell hat auch syntaktischen Zucker.

    
yokto 01.09.2014 16:29
quelle

Tags und Links