Cuenta la frecuencia de las letras en textos usando computación paralela.
El paralelismo consiste en hacer en paralelo cosas que también se pueden hacer de forma secuencial. Un ejemplo común es contar la frecuencia de las letras. Usa el paralelismo para calcular la frecuencia total de cada letra en una lista de textos.
Las tareas son la abstracción principal para escribir código asincrónico en Lean. Son livianas y pueden ejecutarse en paralelo en otro hilo, o de manera concurrente en el mismo hilo.
Las tareas pueden ser puras o impuras.
Las tareas puras se crean con Task.spawn, que acepta un cómputo puro.
Las tareas impuras se crean a partir de cómputos IO usando, por ejemplo, IO.asTask, que eleva un IO α a un Task α dentro de la mónada IO.
En este ejercicio, la función calculateFrequencies es monádica y devuelve un IO (Std.TreeMap Char Nat).
Esto permite usar tareas impuras mediante IO.asTask y también hace posible lanzar tareas puras para cómputos intermedios antes de devolver el valor final.
Como lenguaje funcional, la mayoría de los valores en Lean son persistentes, es decir, inmutables. Las operaciones que parecen modificar un valor en realidad producen un valor nuevo con los cambios solicitados. Esto significa que la memoria a menudo se puede compartir de forma segura entre tareas sin introducir carreras de datos.
Sin embargo, ten en cuenta que no todas las estructuras de datos son igualmente adecuadas para el uso persistente.
Por ejemplo, actualizar un solo elemento de un Array normalmente requiere copiar el array completo.
Lo mismo ocurre con Std.HashSet y Std.HashMap.
Para que estas estructuras de datos sean eficientes, Lean usa el conteo de referencias. Mientras un valor tenga una referencia única, las actualizaciones se pueden hacer de forma destructiva, lo que evita copias innecesarias.
Otras estructuras de datos, como List, Std.TreeSet y Std.TreeMap, están diseñadas para compartir estructura internamente.
Reutilizan los nodos que no cambian cuando se hacen actualizaciones, de modo que varios valores pueden compartir referencias a esos nodos.
Como resultado, modificar una parte de la estructura normalmente no requiere copiar el valor completo.
Esto las hace especialmente adecuadas para compartirlas entre tareas.
El tiempo de ejecución de cada prueba se mide en nanosegundos con IO.monoNanosNow y se muestra junto a los resultados.
Puedes experimentar con distintos enfoques y comprobar su impacto en el rendimiento en tiempo de ejecución.
Regístrate en Exercism para aprender y dominar Lean con 100 ejercicios y mentoría humana real, todo gratis.
Exploramos las diferencias entre concurrencia y paralelismo, viendo los distintos enfoques que adoptan lenguajes como JavaScript, Go, Elixir y Rust.