La plupart des langages fonctionnels utilisent des listes chaînées comme structure de données immuable principale. Pourquoi des listes, et pas par exemple des arbres? Les arbres peuvent également réutiliser des chemins et même des listes de modèles.
La plupart des langages fonctionnels utilisent des listes chaînées comme structure de données immuable principale. Pourquoi des listes, et pas par exemple des arbres? Les arbres peuvent également réutiliser des chemins et même des listes de modèles.
Réponses:
Parce que les listes sont plus simples que les arbres. (Vous pouvez le voir de manière triviale par le fait qu’une liste est un arbre dégénéré, chaque nœud n’ayant qu’un seul enfant.)
La liste des inconvénients est la structure de données récursive la plus simple possible de taille arbitraire.
Lors de la conception du langage de programmation Fortress, Guy Steele a expliqué que, pour les calculs extrêmement parallèles du futur, nos structures de données et notre flux de contrôle devraient être en forme d'arborescence à multiples branches, et non linéaires à l'heure actuelle. Mais pour le moment, la plupart de nos principales bibliothèques de structures de données ont été conçues avec un traitement séquentiel et itératif (ou une récursion finale, peu importe, elles sont identiques), pas un traitement parallèle.
Notez que, par exemple, dans Clojure, dont les structures de données ont été spécialement conçues pour le monde parallèle, "nuageux" et distribué, même des tableaux (appelés "vecteur dans Clojure), probablement la structure de données la plus" linéaire "de tous, sont en réalité mis en oeuvre des arbres.
En résumé, une liste est la structure de données récursive persistante la plus simple possible et il n’était pas nécessaire de choisir un "défaut" plus compliqué. D'autres sont bien sûr disponibles en option, par exemple Haskell a des tableaux, des files d'attente prioritaires, des cartes, des tas, des balises, des tentatives et tout ce que vous pouvez imaginer, mais la valeur par défaut est la simple liste des inconvénients.
data Tree a = Leaf a | Branch a (Tree a) (Tree a)
. Cela renforce votre argument "simplicité".
Sequence
ou de Scala Vector
), mais n’utilisez pas les arbres quand ils ont seulement besoin de les lire car ils peuvent y parvenir en temps réel (par exemple Haskell's Vector
ou F # via .Net ImmutableArray
)
pmap
ping sur un vecteur dans Clojure accède toujours à chaque élément de manière séquentielle; la structure arborescente du vecteur est généralement masquée pour l'utilisateur final.
En fait, ces listes sont des arbres! Vous avez des noeuds avec deux champs, car
et cdr
, qui peuvent contenir plus de tels noeuds ou feuilles. La seule chose qui transforme ces arbres en listes est la convention selon laquelle le lien est interprétécdr
comme un lien vers le nœud suivant dans une liste linéaire et le car
lien comme la valeur du nœud actuel.
Cela dit, je suppose que la prévalence des listes chaînées dans la programmation fonctionnelle est liée à la prévalence de la récursion sur l'itération. Lorsque votre seule construction en boucle est la récursion, vous voulez des structures de données faciles à utiliser avec cela; et les listes chaînées sont parfaites pour cela.