Si vous pouvez utiliser def pour redéfinir les variables, comment est-ce considéré comme immuable?
10
Essayer d'apprendre Clojure et vous ne pouvez pas vous empêcher de savoir continuellement comment Clojure est tout au sujet des données immuables. Mais vous pouvez facilement redéfinir une variable en utilisant defnon? Je comprends que les développeurs de Clojure évitent cela, mais vous pouvez éviter de changer les variables dans n'importe quelle langue de la même manière. Quelqu'un peut-il m'expliquer en quoi cela est différent, parce que je pense que cela manque dans les tutoriels et les livres que je lis.
Comme vous l'avez déjà remarqué, le fait que la mutabilité soit découragée dans Clojure ne signifie pas qu'elle est interdite et qu'il n'y a pas de constructions qui la supportent. Vous avez donc raison de dire que defvotre utilisation peut modifier / muter une liaison dans l'environnement d'une manière similaire à ce que fait l'affectation dans d'autres langues (voir la documentation de Clojure sur les vars ). En modifiant les liaisons dans l'environnement global, vous modifiez également les objets de données qui utilisent ces liaisons. Par exemple:
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
Notez qu'après avoir redéfini la liaison pour x, la fonction fa également changé, car son corps utilise cette liaison.
Comparez cela avec les langages dans lesquels la redéfinition d'une variable ne supprime pas l'ancienne liaison mais la masque uniquement , c'est-à-dire qu'elle la rend invisible dans la portée qui suit la nouvelle définition. Voyez ce qui se passe si vous écrivez le même code dans le 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
Notez qu'après la deuxième définition de x, la fonction futilise toujours la liaison x = 1qui était dans la portée lorsqu'elle a été définie, c'est-à-dire que la liaison val x = 100n'écrase pas la liaison précédente val x = 1.
Conclusion: Clojure permet de muter l'environnement global et de redéfinir les liaisons en son sein. Il serait possible d'éviter cela, comme le font d'autres langages comme SML, mais la defconstruction de Clojure est destinée à accéder à un environnement global et à le muter. En pratique, cela est très similaire à ce que l'affectation peut faire dans des langages impératifs comme Java, C ++, Python.
Pourtant, Clojure fournit de nombreuses constructions et bibliothèques qui évitent la mutation, et vous pouvez faire du chemin sans l'utiliser du tout. Éviter la mutation est de loin le style de programmation préféré dans Clojure.
Éviter la mutation est de loin le style de programmation préféré. Je suggère que cette déclaration s'applique à toutes les langues de nos jours; pas seulement Clojure;)
David Arno
2
Clojure est une question de données immuables
Clojure consiste à gérer l' état mutable en contrôlant les points de mutation (c'est-à-dire Refs, Atoms, Agents et Vars). Bien sûr, tout code Java que vous utilisez via l'interopérabilité peut faire à sa guise.
Mais vous pouvez facilement redéfinir une variable en utilisant def right?
Si vous voulez lier un Var(par opposition à, par exemple, une variable locale) à une valeur différente, alors oui. En fait, comme indiqué dans Vars et le Global Environment , les Vars sont spécifiquement inclus comme l'un des quatre «types de référence» de Clojure (bien que je dirais qu'ils font principalement référence aux s dynamiquesVar là-bas).
Avec Lisps, il y a une longue histoire de réalisation d'activités de programmation exploratoires interactives via le REPL. Cela implique souvent de définir de nouvelles variables et fonctions, ainsi que de redéfinir les anciennes. Cependant, en dehors du REPL, defun a Varest considéré comme une forme médiocre.
Cependant, la modification de la valeur associée à un nom comme celui-ci peut rendre plus difficile la compréhension du comportement de votre programme car il est plus difficile de savoir quelle valeur est associée à un nom ou pourquoi cette valeur peut avoir changé. Clojure dispose d'un ensemble d'outils pour gérer le changement, que vous découvrirez au chapitre 10. En apprenant Clojure, vous constaterez que vous aurez rarement besoin de modifier une association nom / valeur. Voici une façon d'écrire le code précédent:
Ne pourrait-on pas facilement faire la même chose en Ruby? La suggestion donnée est simplement de définir une fonction qui renvoie une valeur. Ruby a aussi des fonctions!
Evan Zamir
Oui je sais. Mais au lieu d'encourager une manière impérative de résoudre le problème proposé (comme changer les liaisons), Clojure adopte le paradigme fonctionnel.
Clojure consiste à gérer l' état mutable en contrôlant les points de mutation (c'est-à-dire
Ref
s,Atom
s,Agent
s etVar
s). Bien sûr, tout code Java que vous utilisez via l'interopérabilité peut faire à sa guise.Si vous voulez lier un
Var
(par opposition à, par exemple, une variable locale) à une valeur différente, alors oui. En fait, comme indiqué dans Vars et le Global Environment , lesVar
s sont spécifiquement inclus comme l'un des quatre «types de référence» de Clojure (bien que je dirais qu'ils font principalement référence aux s dynamiquesVar
là-bas).Avec Lisps, il y a une longue histoire de réalisation d'activités de programmation exploratoires interactives via le REPL. Cela implique souvent de définir de nouvelles variables et fonctions, ainsi que de redéfinir les anciennes. Cependant, en dehors du REPL,
def
un aVar
est considéré comme une forme médiocre.la source
De Clojure pour les braves et les vrais
la source