Pattern matchings y recursividad

En la recursividad, una función se llame a sí misma con distintos parámetros. La ventaja de disponer de pattern matching en Elixir es que podemos escribir código recursivo de una forma muy simple en la que los casos base se teclean como constantes o usando guardas.

La recursión es una técnica fundamental en Elixir que nos permite resolver problemas de forma elegante haciendo que una función se llame a sí misma. Para entenderla mejor, podemos partir del ejemplo clásico del cálculo del factorial. Matemáticamente, el factorial de un número n se define como n multiplicado por el factorial de n-1. Esto se traduce directamente en Elixir con una función que, para calcular el factorial de n, multiplica n por el resultado de llamar a la misma función con n-1.

Sin embargo, no basta con definir la función de esta manera, porque si no establecemos un punto de parada, la función se llamará a sí misma indefinidamente, generando un bucle infinito. Por eso es crucial definir un caso base que detenga la recursión. En el caso del factorial, ese caso base es cuando n es cero, y el resultado es uno. Así, cuando la función llega a factorial de cero, devuelve uno y no se llama a sí misma de nuevo, lo que permite que todas las llamadas anteriores puedan resolverse correctamente.

Podemos implementar esta lógica en Elixir de varias formas. Una opción es usar un condicional if para comprobar si n es cero y devolver uno en ese caso, o calcular la recursión en caso contrario. Pero Elixir nos ofrece una forma más idiomática y clara de hacerlo mediante el pattern matching. Definimos una cláusula de la función para el caso base, por ejemplo factorial(0), que devuelve uno, y otra cláusula para el caso recursivo, que recibe un número n y devuelve n * factorial(n - 1).

Este enfoque aprovecha que Elixir evalúa las definiciones de funciones en orden, por lo que primero intenta hacer match con el caso base y, si no coincide, pasa al caso recursivo. Además, podríamos usar guardas para definir condiciones, pero en este caso el pattern matching directo con el valor cero es más sencillo y expresivo.

Para ilustrar, el código quedaría así:

defmodule Matematicas do
  def factorial(0), do: 1
  def factorial(n), do: n * factorial(n - 1)
end

Con esta definición, al llamar a Matematicas.factorial(5), la función se llamará a sí misma con valores decrecientes hasta llegar a cero, momento en el que devolverá uno y comenzará a resolver todas las multiplicaciones pendientes, resultando en 120.

Es importante recordar que el orden de las definiciones es clave: el caso base debe estar definido antes que el recursivo para que Elixir lo reconozca primero y evite la recursión infinita.

Aunque la recursión puede parecer complicada al principio, en Elixir se basa en estos principios simples y repetitivos: definir claramente cuándo detener la recursión y usar el pattern matching para distinguir los casos. Más adelante, podemos explorar otras funciones y técnicas que nos permitan aprovechar la recursión de manera aún más potente en nuestro día a día con Elixir.

Lista de reproducción
  1. 1
    ¿Qué es Elixir?
    10 minutos
  2. 2
    Instalación de Elixir
    9 minutos
  3. 3
    ¿Qué es la programación funcional? (Como la de Elixir)
    20 minutos
  4. 4
    ¿Cómo funciona la REPL de Elixir?
    7 minutos
  5. 5
    ¿Cómo hacer asignaciones en Elixir?
    7 minutos
  6. 6
    Operadores aritméticos básicos
    6 minutos
  7. 7
    ¿Qué son los tipos de datos de Elixir?
    5 minutos
  8. 8
    Átomos en Elixir
    4 minutos
  9. 9
    Las palabras clave nil, true y false
    6 minutos
  10. 10
    Operadores lógicos de comparación
    8 minutos
  11. 11
    Comparación estricta con ===
    3 minutos
  12. 12
    Operadores lógicos y proposicionales
    8 minutos
  13. 13
    Invocación de funciones
    10 minutos
  14. 14
    Fundamentos de funciones
    9 minutos
  15. 15
    Cadenas de caracteres
    8 minutos
  16. 16
    Entrada y salida estandar de la mano de gets y puts
    9 minutos
  17. 17
    Concatenar e interpolar strings
    9 minutos
  18. 18
    Código fuente en archivos
    9 minutos
  19. 19
    Condicional IF y bloques DO-END
    11 minutos
  20. 20
    IFs anidados, UNLESS y COND
    12 minutos
  21. 21
    Definición de funciones
    11 minutos
  22. 22
    Fundamentos de compilación de módulos
    6 minutos
  23. 23
    Guardas
    8 minutos
  24. 24
    Funciones anónimas
    7 minutos
  25. 25
    Capturar funciones
    4 minutos
  26. 26
    Invocación de funciones dentro del mismo módulo
    7 minutos
  27. 27
    Tuplas
    8 minutos
  28. 28
    Introducción al pattern matching
    8 minutos
  29. 29
    Pattern matching en funciones
    11 minutos
  30. 30
    Las tuplas :ok, :error
    7 minutos
  31. 31
    case
    10 minutos
  32. 32
    Operador pin
    7 minutos
  33. 33
    Pattern matchings y recursividad
    5 minutos
  34. 34
    Listas
    9 minutos
  35. 35
    Operadores y funciones de lista
    10 minutos
  36. 36
    Keyword lists: listas de palabras clave
    8 minutos
  37. 37
    Mapas
    7 minutos
  38. 38
    Pattern matching de mapas y keyword lists
    6 minutos
  39. 39
    Operadores y funciones para mapas y keyword lists
    5 minutos
  40. 40
    Estructuras con defstruct
    11 minutos
  41. 41
    Bitstrings
    11 minutos
  42. 42
    Charlists
    10 minutos
  43. 43
    Funciones de alto orden en Elixir
    5 minutos
  44. 44
    Uso de la función filter
    10 minutos
  45. 45
    Uso de la función map
    7 minutos
  46. 46
    Uso de la función reduce
    9 minutos
  47. 47
    Pipelines
    11 minutos
  48. 48
    Rangos y Streams
    11 minutos
  49. 49
    Funciones recursivas con listas
    14 minutos