Як ви вже помічали, той факт, що в Clojure не змінюється зміна, не означає, що це заборонено і немає конструкцій, які б його підтримували. Отже, ви маєте рацію, що використовуючи def
ви можете змінювати / мутувати прив'язку в оточенні таким чином, як це призначено в інших мовах (див . Документацію Clojure про vars ). Змінюючи прив’язки в глобальному середовищі, ви також змінюєте об'єкти даних, які використовують ці прив'язки. Наприклад:
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
Зауважте, що після перевизначення зв'язування x
функція f
також змінилася, тому що її організм використовує це зв'язування.
Порівняйте це з мовами, в яких переосмислення змінної не видаляє старе прив'язування, а лише затінює його, тобто робить його невидимим у тій області, що надходить після нового визначення. Подивіться, що станеться, якщо ви запишете той самий код у відповідь SML:
- 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
Зауважте, що після другого визначення функції x
, функція f
все ще використовує прив'язку, x = 1
яка була в області дії, коли вона була визначена, тобто зв'язування val x = 100
не замінює попереднє зв'язування val x = 1
.
Підсумок: Clojure дозволяє мутувати глобальне середовище і переробляти прив'язки в ньому. Цього можна було б уникнути, як це роблять інші мови, як SML, але def
конструкція в Clojure призначена для доступу та мутації глобального середовища. На практиці це дуже схоже на те, що завдання можуть виконувати в таких імперативних мовах, як Java, C ++, Python.
Проте Clojure пропонує безліч конструкцій і бібліотек, які уникають мутації, і ви можете пройти довгий шлях, не використовуючи його зовсім. Уникнення мутацій є на сьогодні кращим стилем програмування в Clojure.