Seguimos con concurrencia en Clojure
Las estructuras de datos persistentes, no tiene nada que ver con la persistencia en el disco o dentro de una base de datos. En cambio, se refiere a una estructura de datos que siempre conserva su versión anterior cuando se modifica, lo que permite que el código tenga una vista consistente de los datos ante modificaciones.
Podemos ver esto fácilmente en el REPL:
user=> (def mapv1 {:name "paul" :age 45})
#'user/mapv1
user=> (def mapv2 (assoc mapv1 :sex :male))
#'user/mapv2
user=> mapv1
{:age 45, :name "paul"}
user=> mapv2
{:age 45, :name "paul", :sex :male}
Las estructuras de datos persistentes se comportan como si se hiciera una copia completa cada vez que se modifican. Si esa fuera la forma en que se implementaron realmente, sería muy ineficiente y, por lo tanto, de uso limitado
Afortunadamente, la implementación es mucho más inteligente que eso y hace uso de la estructura compartida.
La estructura de datos persistentes más fácil de entender es la lista. Aquí hay una lista simple:
user=> (def listv1 (list 1 2 3))
#'user/listv1
user=> listv1
(1 2 3)
Y aquí hay un diagrama de cómo se ve en la memoria:
Ahora vamos a crear una versión modificada con cons, que devuelve una copia de la lista con un elemento agregado al frente:
user=> (def listv2 (cons 4 listv1))
#'user/listv2
user=> listv2
(4 1 2 3)
Finalmente, creemos otra versión modificada:
user=> (def listv3 (cons 5 (rest listv1)))
#'user/listv3
user=> listv3
(5 2 3)