Ich würde gerne lernen, wie man in Haskell Diagramme erstellt und einige lokale Operationen daran ausführt, aber die Frage ist nicht spezifisch für Haskell, und anstelle von Diagrammen können wir doppelt verknüpfte Listen betrachten.
Frage: Was wäre eine idiomatische oder empfohlene Methode, um eine doppelt verknüpfte Liste (oder eine andere doppelt verknüpfte oder zirkuläre Datenstruktur) und Operationen darauf in einer Sprache zu implementieren, die hauptsächlich unveränderliche Datenstrukturen unterstützt und befürwortet (Haskell, Clojure usw.)? ? Insbesondere, wie man In-Place-Updates verwendet, die von der Sprache formal verboten sind?
Ich kann mir leicht vorstellen, dass es aufgrund der Faulheit der Sprache möglicherweise nicht erforderlich ist, die gesamte Liste sofort zu kopieren, wenn eine lokale Operation für eine doppelt verknüpfte Liste ausgeführt wird (z. B. wenn ein Element eingefügt wird). Da die Liste jedoch doppelt verknüpft ist, kann keiner der alten Knoten in der neuen Version der Liste verwendet werden, wenn sie an einer Stelle geändert wird, und sie müssten früher oder später irgendwie markiert, kopiert und mit Müll gesammelt werden . Offensichtlich sind dies redundante Operationen, wenn nur die aktualisierte Kopie der Liste verwendet werden soll, aber sie würden einen "Overhead" hinzufügen, der proportional zur Größe der Liste ist.
Bedeutet dies, dass unveränderliche Daten für solche Aufgaben einfach unangemessen sind und funktionale deklarative Sprachen ohne "native" Unterstützung für veränderbare Daten nicht so gut sind wie zwingende? Oder gibt es eine schwierige Problemumgehung?
PS Ich habe einige Artikel und Präsentationen zu diesem Thema im Internet gefunden, hatte aber Schwierigkeiten, ihnen zu folgen, während ich denke, dass die Antwort auf diese Frage nicht mehr als einen Absatz und vielleicht ein Diagramm umfassen sollte ... Ich meine, wenn es welche gibt Keine "funktionale" Lösung für dieses Problem, die Antwort lautet wahrscheinlich "benutze C". Wenn es eine gibt, wie kompliziert kann sie dann sein?
Verwandte Fragen
"Datenstrukturen in der funktionalen Programmierung" . Meine spezielle Frage zur Verwendung von In-Place-Updates anstelle ineffizienter Alternativen wird dort nicht erörtert.
"Interne Mutation persistenter Datenstrukturen" . Dort scheint der Schwerpunkt auf der Implementierung auf niedriger Ebene in einer nicht spezifizierten Sprache zu liegen, während meine Frage die richtige Wahl einer Sprache (funktional oder anderweitig) und mögliche idiomatische Lösungen in funktionalen Sprachen betrifft.
Relevante Zitate
Rein funktionale Programmiersprachen ermöglichen es, viele Algorithmen sehr präzise auszudrücken, aber es gibt einige Algorithmen, bei denen der aktuelle aktualisierbare Zustand eine entscheidende Rolle zu spielen scheint. Für diese Algorithmen scheinen rein funktionale Sprachen, denen der aktualisierbare Zustand fehlt, von Natur aus ineffizient zu sein ( [Ponder, McGeer und Ng, 1988] ).
- John Launchbury und Simon Peyton Jones, Lazy Functional State Threads (1994), auch John Launchbury und Simon Peyton Jones, State in Haskell (1995). Diese Arbeiten stellen den ST
monadischen Konstruktor in Haskell vor.
DiffArray
Typ implementiert . Wenn ich mir die Quelle des Diffarray- Pakets anschaue , sehe ich 91 Vorkommen von unsafePerformIO
. Die Antwort auf meine Frage lautet anscheinend "Ja, nein, rein funktionale Sprachen mit unveränderlichen Daten sind nicht für die Implementierung von Algorithmen geeignet, die normalerweise auf direkten Aktualisierungen beruhen".
Map
, IntMap
oder HashMap
) als Speicher- und Knoten - IDs der verknüpften Knoten enthalten zu machen. "Alle Probleme in der Informatik können durch eine andere Indirektionsebene gelöst werden."