Compte la fréquence des lettres dans des textes en utilisant le calcul parallèle.
Le parallélisme consiste à faire en parallèle des choses qui peuvent aussi être faites de manière séquentielle. Un exemple courant est le comptage de la fréquence des lettres. Utilise le parallélisme pour calculer la fréquence totale de chaque lettre dans un tableau de textes.
Les tâches sont l'abstraction principale pour écrire du code asynchrone en Lean. Elles sont légères et peuvent s'exécuter en parallèle sur un autre fil d'exécution, ou concurremment sur le même fil.
Les tâches peuvent être pures ou impures.
Les tâches pures sont créées avec Task.spawn, qui accepte un calcul pur.
Les tâches impures sont créées à partir de calculs IO en utilisant, par exemple, IO.asTask, qui transforme un IO α en Task α au sein de la monade IO.
Dans cet exercice, la fonction calculateFrequencies est monadique et renvoie un IO (Std.TreeMap Char Nat).
Cela permet d'utiliser des tâches impures via IO.asTask, et rend aussi possible de créer des tâches pures pour des calculs intermédiaires avant de renvoyer la valeur finale.
En tant que langage fonctionnel, la plupart des valeurs en Lean sont persistantes, c'est-à-dire immuables. Les opérations qui semblent modifier une valeur produisent en réalité une nouvelle valeur avec les changements demandés. Cela signifie que la mémoire peut souvent être partagée sans risque entre les tâches, sans introduire de courses de données.
Remarque toutefois que toutes les structures de données ne se prêtent pas aussi bien à un usage persistant.
Par exemple, mettre à jour un seul élément d'un Array nécessite généralement de copier le tableau entier.
Il en va de même pour Std.HashSet et Std.HashMap.
Pour rendre ces structures de données efficaces, Lean a recours au comptage de références. Tant qu'une valeur a une référence unique, les mises à jour peuvent être effectuées de manière destructive, ce qui évite des copies inutiles.
D'autres structures de données, comme List, Std.TreeSet et Std.TreeMap, sont conçues pour partager leur structure en interne.
Elles réutilisent les nœuds inchangés lors des mises à jour, de sorte que plusieurs valeurs peuvent partager des références vers ces nœuds.
Par conséquent, modifier une partie de la structure ne nécessite généralement pas de copier la valeur entière.
Cela les rend particulièrement bien adaptées au partage entre tâches.
Le temps d'exécution de chaque test est mesuré en nanosecondes avec IO.monoNanosNow et affiché à côté des résultats.
Tu peux expérimenter différentes approches et observer leur impact sur les performances d'exécution.
Inscris-toi sur Exercism pour apprendre et maîtriser Lean avec 100 exercices, et un vrai mentorat humain, le tout gratuitement.
On explore les différences entre concurrence et parallélisme, en examinant les différentes approches adoptées par des langages comme JavaScript, Go, Elixir et Rust.