Ich bin neu in Haskell (ein paar Monate). Ich habe ein Haskell-Programm, das einen großen Ausdruck DAG (kein Baum, ein DAG), möglicherweise tief und mit mehreren zusammenführenden Pfaden (dh die Anzahl der verschiedenen Pfade von der Wurzel zu Blättern ist riesig) assembliert. Ich brauche einen schnellen Weg, um diese dags auf Gleichheit zu testen. Die Standard-Ableitung von Eq wird nur recurse, die gleichen Knoten mehrmals erforschend. Momentan verursacht dies, dass mein Programm 60 Sekunden für relativ kleine Ausdrücke benötigt und nicht einmal für größere. Der Profiler zeigt an, dass er die meiste Zeit damit beschäftigt ist, die Gleichheit zu prüfen. Ich möchte eine benutzerdefinierte EQ implementieren, die dieses Problem nicht hat. Ich habe keine Möglichkeit, dieses Problem zu lösen, das nicht viel Umschreiben erfordert. Ich möchte deine Gedanken hören.Eq-Test für große DAG-Strukturen in Haskell
Mein erster Versuch war, Baumknoten mit einem Hash zu instrumentieren, den ich inkrementell berechne, indem ich Data.Hashable.hash
benutze, während ich den Baum baue. Dieser Ansatz gab mir eine einfache Möglichkeit zu testen, zwei Dinge sind nicht gleich, ohne tief in die Struktur zu schauen. Aber oft in dieser DAG, wegen der Wege in der DAG Fusion, sind die Strukturen in der Tat gleich. Die Hashes sind also gleich, und ich gehe wieder zum vollständigen Gleichheitstest über.
Wenn ich einen Weg zur physischen Gleichheit hätte, dann würden viele meiner Probleme hier verschwinden: Wenn sie physisch gleich sind, dann ist es das. Ansonsten, wenn der Hash anders ist, dann ist es das. Gehen Sie nur tiefer, wenn sie physisch nicht gleich sind, aber ihr Hash stimmt zu.
Ich könnte auch Git imitieren, und berechnen Sie eine SHA1 pro Knoten, um zu entscheiden, ob sie gleiche Periode sind (keine Notwendigkeit zu recurse). Ich weiß genau, dass dies helfen würde, denn wenn ich die Gleichheit vollständig in Bezug auf die Hash-Gleichheit entscheiden lasse, dann läuft das Programm in Zehn-Millisekunden für die größten Ausdrücke. Dieser Ansatz hat auch den schönen Vorteil, dass, wenn aus irgendeinem Grund zwei gleiche dags physikalisch nicht gleich aber inhaltsgleich sind, ich in der Lage wäre, sie auch in diesem Fall schnell zu erkennen. (Mit Ids muss Id an diesem Punkt noch eine Traversierung durchführen). Also ich mag die Semantik mehr.
Dieser Ansatz beinhaltet jedoch viel mehr Arbeit als nur den Aufruf der Data.Hashable.hash
-Funktion, weil ich es für jede Variante des dag-Knotentyps ableiten muss. Und außerdem habe ich mehrere dag-Darstellungen mit etwas anderen Knotendefinitionen, also müsste ich diese Hashing-Trick-Sache zweimal oder öfter machen, wenn ich mich dazu entscheide, mehr Repräsentationen hinzuzufügen.
Was würden Sie tun?
Fragen Sie, wie Sie '(==)' mit einer benutzerdefinierten Funktion definieren oder welche benutzerdefinierte Funktion Ihren Anforderungen am besten entspricht? Die Frage ist ein wenig aufgebläht/verwirrt wie es jetzt steht ... Übrigens, ich denke nicht, dass "physische Gleichheit", wie du es aus anderen Sprachen kennst, in Haskell existiert, du definierst einfach deine 'Klasse Eq a wo (==) .... und das ist es ... – mb21
@ mb21 Er fragt sich entweder, wie man eine effiziente Instanz für 'Eq' definiert oder wie man eine Datenstruktur für seine DAG definiert, für die die Standardinstanz für' Eq' effizient ist. .. nicht sicher, welche der beiden, und ohne Code geben wir wenig Hilfe. – Bakuriu