Como ya notó, el hecho de que se desaconseja la mutabilidad en Clojure no significa que esté prohibido y que no haya construcciones que lo respalden. Entonces tiene razón en que al usarlo def
puede cambiar / mutar un enlace en el entorno de forma similar a lo que hace la asignación en otros idiomas (consulte la documentación de Clojure en vars ). Al cambiar los enlaces en el entorno global, también cambia los objetos de datos que usan estos enlaces. Por ejemplo:
user=> (def x 1)
#'user/x
user=> (defn f [y] (+ x y))
#'user/f
user=> (f 1)
2
user=> (def x 100)
#'user/x
user=> (f 1)
101
Tenga en cuenta que después de redefinir el enlace para x
, la función también f
ha cambiado, porque su cuerpo usa ese enlace.
Compare esto con los idiomas en los que la redefinición de una variable no elimina el enlace anterior, sino que solo lo sombrea , es decir, lo hace invisible en el alcance que viene después de la nueva definición. Vea lo que sucede si escribe el mismo código en SML REPL:
- val x = 1;
val x = 1 : int
- fun f y = x + y;
val f = fn : int -> int
- f 1;
val it = 2 : int
- val x = 100;
val x = 100 : int
- f 1;
val it = 2 : int
Tenga en cuenta que después de la segunda definición de x
, la función f
todavía utiliza el enlace x = 1
que estaba en el alcance cuando se definió, es decir, el enlace val x = 100
no sobrescribe el enlace anterior val x = 1
.
En pocas palabras: Clojure permite mutar el entorno global y redefinir los enlaces en él. Sería posible evitar esto, como lo hacen otros lenguajes como SML, pero la def
construcción en Clojure está destinada a acceder y mutar un entorno global. En la práctica, esto es muy similar a lo que la asignación puede hacer en lenguajes imperativos como Java, C ++, Python.
Aún así, Clojure proporciona muchas construcciones y bibliotecas que evitan la mutación, y puede recorrer un largo camino sin usarlo en absoluto. Evitar la mutación es, con mucho, el estilo de programación preferido en Clojure.
Clojure se trata de administrar el estado mutable controlando los puntos de mutación (es decir,
Ref
s,Atom
s,Agent
syVar
s). Aunque, por supuesto, cualquier código Java que use a través de interoperabilidad puede hacer lo que le plazca.Si quiere decir unir a
Var
(en lugar de, por ejemplo, una variable local) a un valor diferente, entonces sí. De hecho, como se señaló en Vars y el entorno global , losVar
s se incluyen específicamente como uno de los cuatro "tipos de referencia" de Clojure (aunque diría que se refieren principalmente a los dinámicosVar
allí).Con Lisps, existe una larga historia de realización de actividades de programación interactivas y exploratorias a través de REPL. Esto a menudo implica definir nuevas variables y funciones, así como redefinir las antiguas. Sin embargo, fuera de la REPL, la lectura
def
de aVar
se considera deficiente.fuente
De Clojure para los valientes y verdaderos
fuente