Jak już zauważyłeś, fakt, że w Clojure odradza się zmienność, nie oznacza, że jest zabroniony i nie ma żadnych konstrukcji, które by to wspierały. Masz więc rację, że używając def
możesz zmienić / mutować powiązanie w środowisku w sposób podobny do przypisania w innych językach (zobacz dokumentację Clojure na temat vars ). Zmieniając powiązania w środowisku globalnym, zmieniasz także obiekty danych korzystające z tych powiązań. Na przykład:
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
Zauważ, że po ponownym zdefiniowaniu wiązania x
funkcja f
również się zmieniła, ponieważ jego ciało używa tego wiązania.
Porównaj to z językami, w których redefinicja zmiennej nie usuwa starego powiązania, a jedynie zacienia go, tzn. Czyni go niewidocznym w zakresie, który pojawia się po nowej definicji. Zobacz, co się stanie, jeśli napiszesz ten sam kod w 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
Zauważ, że po drugiej definicji x
funkcja f
nadal używa powiązania, x = 1
które było w zasięgu, gdy zostało zdefiniowane, tzn. Powiązanie val x = 100
nie zastępuje poprzedniego powiązania val x = 1
.
Konkluzja: Clojure pozwala mutować globalne środowisko i redefiniować w nim powiązania. Można by tego uniknąć, tak jak robią to inne języki, takie jak SML, ale def
konstrukcja w Clojure ma na celu uzyskiwanie dostępu i mutowanie środowiska globalnego. W praktyce jest to bardzo podobne do tego, co przypisanie może zrobić w imperatywnych językach, takich jak Java, C ++, Python.
Mimo to Clojure zapewnia wiele konstrukcji i bibliotek, które unikają mutacji, i możesz przejść długą drogę, nie używając go wcale. Unikanie mutacji jest zdecydowanie preferowanym stylem programowania w Clojure.
Clojure polega na zarządzaniu stanem zmiennym poprzez kontrolowanie punktów mutacji (tj.
Ref
S,Atom
s,Agent
s iVar
s). Chociaż oczywiście każdy kod Java, którego używasz przez interop, może robić, co chcesz.Jeśli masz na myśli powiązanie
Var
(w przeciwieństwie np. Zmiennej lokalnej) z inną wartością, to tak. W rzeczywistości, jak zauważono w Vars i globalnym środowisku ,Var
są one specjalnie uwzględnione jako jeden z czterech „typów referencyjnych” Clojure (choć powiedziałbym, że odnoszą się głównie do dynamicznychVar
).W Lisps istnieje długa historia wykonywania interaktywnych, eksploracyjnych działań programistycznych za pośrednictwem REPL. Często wiąże się to z definiowaniem nowych zmiennych i funkcji, a także redefiniowaniem starych. Jednak poza REPL, ponownie
def
ingVar
jest uważany za słabą formę.źródło
Od Clojure for the Brave and True
źródło