you can do this with an altered state and without it with the same idea. You run a function that takes the initial state of the addresses, and the state you want to add, which then returns a new set of addresses, including the new state. He does this without destroying the original, of course, because someone can look at it.
determine the base address book:
user> (def addresses [])
Define a new address book containing the new value:
user> (def book-with-dirk (conj addresses {:name "dirk" :address "123 internet st."}))
which does not change the base address book, but creates a new address book, which effectively combines the original address book with the new value for dirk. Thus, the addresses remain the same.
user> addresses []
You can also use managed mutable state to maintain the contents of identity names with names in a functional order. the original value in the address atom still exists if someone is looking at it (and otherwise is GCd)
user> (def addresses (atom []))
create a new address book, which, as above, includes dirk, in addition, the following value is also created in the address identifier:
user> (def book-with-dirk (swap! addresses conj {:name "dirk" :address "123 internet st."}))
now book-with-dirk is the value that contains the book with dirk in it.
user> book-with-dirk [{:name "dirk", :address "123 internet st."}]
and the address also contains the new meaning.
user> @addresses [{:name "dirk", :address "123 internet st."}]
If I then add Joe, book-with-dirk will not change
user> (swap! addresses conj {:name "Joe" :address "321 internet st."}) [{:name "dirk", :address "123 internet st."} {:name "Joe", :address "321 internet st."}] user> book-with-dirk [{:name "dirk", :address "123 internet st."}]