2010-09-03 7 views
2
1: user=> (def some-account {:number :any­-number :balance :any­-balance :bank :any­-bank}) 
2: #'user/some-account 
3: user=> (contains? some-account :bank) 
4: true 
5: user=> (assoc some-account :owner :any-owner) 
6: {:owner :any-owner, :number :any­-number, :balance :any­-balance, :bank :any­-bank} 
7: user=> (contains? some-account :owner) 
8: false 
9: user=> (def some-account (assoc some-account :owner :any-owner)) 
10: #'user/some-account 
11: user=> (contains? some-account :owner) 
12: true 
13: user=> (dissoc some-account :owner) 
14: {:number :any-­number, :balance :any­-balance, :bank :any-­bank} 
15: user=> (contains? some-account :owner) 
16: true 

Quelqu'un peut-il expliquer ce code?Quelqu'un peut-il expliquer ce code?

Pourquoi, après (assoc some-account :owner :any-owner), est-ce que (contains? some-account :owner) renvoie false?

Pourquoi, seulement après (def some-account (assoc some-account :owner :any-owner))(contains? some-account :owner) renvoie true? Pourquoi, après (dissoc some-account :owner), est-ce que (contains? some-account :owner) renvoie true?

J'ai essayé de dire (def some-account (assoc some-account :owner :any-owner)) à l'instinct. Mais pourquoi cela fonctionne-t-il de cette façon?

Répondre

2

Dans Clojure tous les types de données sont immuables. Par conséquent, l'opération assoc sur la carte some-account ne le modifie pas (contrairement à l'opération put sur java.util.Map en Java) et produit une nouvelle carte. C'est pourquoi l'opération countain? renvoie false. Lorsque vous faites

(def some-account (assoc some-account :owner :any-owner)) 

vous attrapez la valeur de retour de l'opération et l'affectation assoc à la variable some-account. Dans un sens, vous le redéfinissez. Plus tard, l'opération contain? renvoie true.

6

Les cartes dans Clojure sont immuables. C'est-à-dire que les fonctions de mise à jour, au lieu de modifier la carte d'origine, renvoient une nouvelle carte mise à jour.

les opérations suivantes:

user=> (def some-account {:number :any­-number :balance :any­-balance :bank :any-bank}) 
#'user/some-account 
user=> (contains? some-account :bank) 
true 
user=> (def updated-map (assoc some-account :owner :any-owner)) 
#'user/updated-map 
user=> (contains? updated-map :owner) 
true 
user=> 
+0

bonne introduction dans le codage propre :) – Belun

1

parce assoc et dissoc retour nouveaux objekts et ne changent pas un compte

3

Il est toujours bon de noter que lorsque les fonctions de mise à jour produire une nouvelle carte, ils ne copient pas l'ancien ils produisent une nouveau qui partage toutes les parties qui n'ont pas changé avec l'ancien et ne remplace que les parties requises par les changements.

Ce partage structurel est très important pour tous les langages fonctionnels avec [structures de données immuables] [1]

[1]: http://clojure.org/functional_programming#Functional Programmation - Structures de données Immuable

1

Imaginez que vous utilisiez un nombre au lieu d'une carte:

user> (def s 3) 
#'user/s 
user> (= s 3) 
true 
user> (+ 1 s) 
4 
user> (= s 4) 
false 
user> (def s (+ 1 s)) ;;don't do this! changing definitions shouldn't be used in a program, only at the REPL for trying things out! 
#'user/s 
user> (= s 4) 
true 
user> (- s 1) 
3 
user> (= s 4) 

Dans Clojure, la plupart des valeurs se comportent comme des nombres. Il y a des choses mutables, mais elles sont cachées derrière des interfaces cryptiques. Beaucoup de programmation peut être faite sans eux. Mais comment pouvons-nous programmer sans mutation de variables?

Vous avez peut-être vu la fonction factoriel

(defn factorial [n] 
     (if (< n 2) 1 
      (* n (factorial (dec n))))) 

user> (factorial 5) 
120 

Voici une fonction similaire qui construit une carte de la même manière

(defn char-map [n] 
     (if (< n 0) {} 
      (assoc (char-map (dec n)) n (char n)))) 

user> (char-map 10) 
{various control characters..} 

Ce style est étrange au début, mais finit par devenir naturel. Quand je pense à quelque chose à programmer ces jours-ci, je pense souvent à la solution récursive avant la boucle impérative.

Ce sont deux façons différentes de voir la même chose.

Il est généralement facile de traduire entre eux, de sorte que si vous pouvez penser à une façon de le faire, vous avez déjà pensé à l'autre. Mais cela demande de la pratique, comme apprendre à parler le latin.

Il y a certains avantages dans la clarté de la pensée et la sécurité des threads à ce que les choses ne changent pas après les avoir créées. Les mathématiciens semblent particulièrement le préférer.

Questions connexes