Как вы уже заметили, тот факт, что изменчивость в 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
также изменилась, поскольку ее тело использует эту привязку.
Сравните это с языками, в которых переопределение переменной не удаляет старую привязку, а только затеняет ее, т. Е. Делает ее невидимой в области видимости, следующей за новым определением. Посмотрите, что произойдет, если вы напишите тот же код в REPL 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.
Clojure - это управление изменяемым состоянием путем управления точками мутации (т. Е.
Ref
S,Atom
s,Agent
s иVar
s). Хотя, конечно, любой код Java, который вы используете через взаимодействие, может делать то, что пожелает.Если вы хотите связать
Var
(в отличие, например, локальную переменную) с другим значением, тогда да. На самом деле, как отмечалось в Vars и Global Environment ,Var
s специально включены как один из четырех «ссылочных типов» Clojure (хотя я бы сказал, что они в основном ссылаются на динамическиеVar
s там).С Лиспом существует долгая история выполнения интерактивных, поисковых программ через REPL. Это часто включает определение новых переменных и функций, а также переопределение старых. Тем не менее, за пределами REPL,
def
aVar
считается плохой формой.источник
От Clojure для Храбрых и Истинных
источник