Ich kann # 2 nicht wirklich beantworten, ohne mich zu verlaufen (es gibt zu viele Dimensionen, entlang derer Sie diese Strukturen vergleichen können), aber für # 3 ist die Antwort ziemlich einfach.
Verwenden Sie eine zwingende Datenstruktur, wenn: (a) absolut kein Aliasing vorliegt oder (b) Sie Aliasing wirklich für eine effiziente Übertragung verwenden müssen.
Wenn es überhaupt kein Aliasing Ihrer Datenstruktur gibt, nutzen Sie nicht die Tatsache, dass funktionale Datenstrukturen persistent sind. Es gibt also keinen Grund, für ihre Kosten zu bezahlen. Dieser Rat hat zwei Vorbehalte. Erstens mögen Sie die Einfachheit der Implementierung einer funktionalen Datenstruktur bevorzugen: Wenn Sie das Löschen für einen funktionierenden rot-schwarzen Baum implementieren, werden Sie verflucht, aber wenn Sie das Löschen in einem zwingenden rot-schwarzen Baum mit übergeordneten Zeigern implementieren, werden Sie über Selbstmord nachdenken. Zweitens kann die Zuweisung in einer gc-Sprache teurer sein als erwartet, da durch Schreibvorgänge Datenstrukturen aus der jungen Generation entfernt werden können. Wir haben wirklich keine gute Theorie zu Cache-Effekten und GC, daher haben Sie keine andere Wahl, als Benchmarking durchzuführen.
Zweitens, wenn Sie einen Broadcast-Kanal benötigen, ist eine gemeinsam genutzte Datenstruktur eine hervorragende Möglichkeit, dies zu tun. Mit einer zeitkonstanten Aktualisierung können Sie beliebig vielen anderen Personen mitteilen, dass sich ein Wert geändert hat. (Aus diesem Grund ist Union-Find eine so großartige Datenstruktur.) Bei einem rein funktionalen Setup müssen Sie entweder alle anderen Personen ändern oder ihnen abstrakte Zeiger in einen Zustand geben, den Sie manuell codieren (was eine Art stumpf ist) etwas zu tun).
Wenn Sie entweder nicht über Aliasing und Objektbesitz nachdenken möchten oder wenn Sie mehrere Versionen derselben Datenstruktur benötigen (Sie benötigen beispielsweise sowohl eine neue als auch eine alte Version), verwenden Sie einfach eine funktionale Datenstruktur.
Der Ort, an dem ich es am schwierigsten finde, diesem Rat zu folgen, sind Graph-Algorithmen. Es gibt viele wirklich elegante imperative Graph-Algorithmen, aber es ist häufig der Fall (z. B. beim Schreiben von Compilern), dass Sie auch Persistenz wünschen. Normalerweise versuchen die Leute, den Unterschied aufzuteilen und den coolen Imperativ-Algorithmus zu verwenden, aber versuchen, die Versionierung auf die Seite zu schrauben, um die Persistenz zu erhalten. Dies ist im Allgemeinen ziemlich schrecklich, voller Fehler und neigt dazu, den Leistungsvorteil des imperativen Algorithmus zu verlieren.