Cuenta la frecuencia de las letras en textos mediante computación en paralelo.
El paralelismo consiste en hacer en paralelo cosas que también se pueden hacer de forma secuencial. Un ejemplo habitual es contar la frecuencia de letras. Utiliza el paralelismo para calcular la frecuencia total de cada letra en una lista de textos.
Tareas son la abstracción principal para escribir código asíncrono en Lean. Son ligeras y pueden ejecutarse en paralelo en otro hilo, o de forma concurrente en el mismo hilo.
Las tareas pueden ser puras o impuras.
Las tareas puras se crean con Task.spawn, que acepta un cálculo puro.
Las tareas impuras se crean a partir de cálculos 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 crear tareas puras para cálculos 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 nuevo valor con los cambios solicitados. Esto significa que la memoria a menudo puede compartirse de forma segura entre tareas sin introducir carreras de datos.
Ten en cuenta, sin embargo, que no todas las estructuras de datos son igual de adecuadas para el uso persistente.
Por ejemplo, actualizar un solo elemento de un Array normalmente requiere copiar el array entero.
Lo mismo ocurre con Std.HashSet y Std.HashMap.
Para que este tipo de estructuras de datos sean eficientes, Lean utiliza el recuento de referencias. Mientras un valor tenga una referencia única, las actualizaciones pueden realizarse de forma destructiva, evitando copias innecesarias.
Otras estructuras de datos, como List, Std.TreeSet y Std.TreeMap, están diseñadas para compartir estructura internamente.
Reutilizan los nodos sin cambios cuando se realizan 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 entero.
Esto las hace especialmente adecuadas para compartir 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.