Pergunta

I'm fairly new to Clojure and I'm having a difficult time understanding what's happening behind the scenes with the following code:

; Associate the symbol 'fruits to the value ["apple" "banana"]
(def fruits ["apple" "banana"]) ; returns the var #'user/fruits
(count fruits) ; returns 2

(def fruits ["cherry" "orange" "grapes"]) ; returns the var #'user/fruits
(count fruits) ; returns 3
  1. Is each "def" form returning a NEW var data structure that's named #'user/fruits?
  2. It seems like the symbol 'fruits is bound to a different var after each "def" form - is this because whatever structure that represents the binding is a mutable data structure?
Foi útil?

Solução 2

From the documentation:

Namespaces:

Namespaces are mappings from simple (unqualified) symbols to Vars and/or Classes. Vars can be interned in a namespace, using def or any of its variants, in which case they have a simple symbol for a name and a reference to their containing namespace, and the namespace maps that symbol to the same var.

Vars:

Vars provide a mechanism to refer to a mutable storage location that can be dynamically rebound (to a new storage location) on a per-thread basis.

So, both namespaces and vars are mutable. In the example you give, the first occurrence of def creates a new Var and interns it (i.e. adds a new mapping to it) in the current namespace. The second occurrence of def resets the root binding of the existing Var, without altering the namespace mappings.

When you evaluate some code that contains the symbol of a var that you've defined (assuming it's not shadowed by any local lexical bindings), the compiler first looks up the var mapped to that symbol, and then gets the current value for that var.

Outras dicas

For your first questions: No it is instead actually changing the value contained in the Var fruits rather than making a new one:

 user> (let [old-fruits #'fruits] 
         (def fruits ["cherry" "orange" "grapes"]) 
         (identical? old-fruits #'fruits))
true

If we save a reference to the fruits Var (#' is shorthand for referencing a Var itself, not its contents) then redefine it, the identical? function tells us these are the same object.

For the second question: Namespaces are a mutable data structure that maps symbols to vars. They are not persistent, in the sense that the rest of Clojure's data structures are, and are updated in place. It is worth noting that vars and namespaces are entirely distinct things. While namespaces provide name lookup and typically resolve names to vars they them selves have little to do with vars. You can store vars in anything you would like, and you don't strictly speaking have to use namespaces to keep track of your vars. Vars also provide more functionality than namespaces (or at least different functionality). They have per-thread binding so you can bind a var to a new value safely on one thread without the change affecting other threads.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top