Je voudrais apprendre à créer des graphiques et à effectuer des opérations locales sur eux dans Haskell, mais la question n'est pas spécifique à Haskell, et au lieu de graphiques, nous pouvons envisager des listes doublement liées.
Question: Quelle serait une manière idiomatique ou recommandée d'implémenter une liste doublement liée (ou une autre structure de données doublement liée ou circulaire) et des opérations sur celle-ci dans un langage qui soutient et préconise principalement des structures de données immuables (Haskell, Clojure, etc.) ? En particulier, comment utiliser les mises à jour sur place, qui sont formellement interdites par la langue?
Je peux facilement imaginer que si une opération locale est effectuée sur une liste doublement liée (si un élément est inséré, par exemple), il peut ne pas être nécessaire de copier la liste entière immédiatement en raison de la paresse de la langue. Cependant, étant donné que la liste est doublement liée, si elle est modifiée à un endroit, aucun des anciens nœuds ne peut être utilisé dans la nouvelle version de la liste, et ils devraient être marqués, copiés, récupérés tôt ou tard. . Évidemment, ce sont des opérations redondantes si seule la copie mise à jour de la liste doit être utilisée, mais elles ajouteraient une "surcharge" proportionnelle à la taille de la liste.
Cela signifie-t-il que pour de telles tâches, les données immuables sont tout simplement inappropriées et que les langages déclaratifs fonctionnels sans prise en charge "native" des données mutables ne sont pas aussi bons que les langages impératifs? Ou, y a-t-il une solution de contournement délicate?
PS J'ai trouvé quelques articles et présentations sur ce sujet sur Internet mais j'ai eu du mal à les suivre, alors que je pense que la réponse à cette question ne devrait pas prendre plus d'un paragraphe et peut-être un schéma ... Je veux dire, s'il y a pas de solution "fonctionnelle" à ce problème, la réponse est probablement "utiliser C". S'il y en a un, dans quelle mesure cela peut-il être compliqué?
Questions connexes
"Structures de données en programmation fonctionnelle" . Ma question spécifique sur l'utilisation des mises à jour sur place au lieu d'alternatives inefficaces n'est pas abordée ici.
"Mutation interne de structures de données persistantes" . Là, l'accent semble être mis sur la mise en œuvre de bas niveau dans un langage non spécifié, alors que ma question porte sur le bon choix d'un langage (fonctionnel ou non) et sur les solutions idiomatiques possibles dans les langages fonctionnels.
Citations pertinentes
Les langages de programmation purement fonctionnels permettent à de nombreux algorithmes d'être exprimés de manière très concise, mais il existe quelques algorithmes dans lesquels l'état de mise à jour sur place semble jouer un rôle crucial. Pour ces algorithmes, les langages purement fonctionnels, qui n'ont pas d'état pouvant être mis à jour, semblent intrinsèquement inefficaces ( [Ponder, McGeer et Ng, 1988] ).
- John Launchbury et Simon Peyton Jones, Lazy Functional State Threads (1994), ainsi que John Launchbury et Simon Peyton Jones, State in Haskell (1995). Ces articles présentent le ST
constructeur de type monadique à Haskell.
DiffArray
type. En regardant la source du paquet diffarray , je vois 91 occurrences de unsafePerformIO
. Il semble que la réponse à ma question soit "oui, non, les langages purement fonctionnels avec des données immuables ne sont pas appropriés pour implémenter des algorithmes qui reposent normalement sur des mises à jour sur place".
Map
, IntMap
ou HashMap
) en tant que stockage et de faire des nœuds contiennent des ID des noeuds liés. "Tous les problèmes en informatique peuvent être résolus par un autre niveau d'indirection."