En la programación funcional, dado que casi toda la estructura de datos es inmutable, cuando el estado tiene que cambiar, se crea una nueva estructura. ¿Esto significa mucho más uso de memoria?
Eso depende de la estructura de datos, los cambios exactos que realizó y, en algunos casos, el optimizador. Como un ejemplo, consideremos anteponer a una lista:
list2 = prepend(42, list1) // list2 is now a list that contains 42 followed
// by the elements of list1. list1 is unchanged
Aquí el requisito de memoria adicional es constante, al igual que el costo de tiempo de ejecución de las llamadas prepend
. ¿Por qué? Porque prepend
simplemente crea una nueva celda que tiene 42
como cabeza y list1
como cola. No tiene que copiar o iterar list2
para lograr esto. Es decir, a excepción de la memoria requerida para almacenar 42
, list2
reutiliza la misma memoria utilizada por list1
. Como ambas listas son inmutables, este intercambio es perfectamente seguro.
De manera similar, cuando se trabaja con estructuras de árbol equilibradas, la mayoría de las operaciones requieren solo una cantidad logarítmica de espacio adicional porque todo, pero una ruta del árbol puede ser compartida.
Para las matrices, la situación es un poco diferente. Es por eso que, en muchos lenguajes FP, las matrices no se usan con tanta frecuencia. Sin embargo, si hace algo así arr2 = map(f, arr1)
y arr1
nunca se vuelve a usar después de esta línea, un optimizador inteligente puede crear código que mute en arr1
lugar de crear una nueva matriz (sin afectar el comportamiento del programa). En ese caso, el rendimiento será como en un lenguaje imperativo, por supuesto.