回答:
すでにお気づきのとおり、Clojureで可変性が推奨されていないという事実は、それが禁止されていること、およびそれをサポートする構成がないことを意味するものではありません。そのdef
ため、他の言語での割り当てと同様に、環境でバインディングを変更/変更できることは正しいです(varsに関するClojureのドキュメントを参照)。グローバル環境でバインディングを変更すると、これらのバインディングを使用するデータオブジェクトも変更されます。例えば:
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 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
の2番目の定義後もx
、関数は定義時にスコープ内にあっf
たバインディングx = 1
を引き続き使用することにval x = 100
注意してくださいval x = 1
。つまり、バインディングは前のバインディングを上書きしません。
結論:Clojureを使用すると、グローバル環境を変更して、その中でバインディングを再定義できます。SMLのような他の言語と同じように、これを回避することは可能ですが、def
Clojure の構成はグローバル環境にアクセスして変更することを目的としています。実際には、これは、Java、C ++、Pythonなどの命令型言語で割り当てが実行できることと非常によく似ています。
それでも、Clojureは変異を回避する多くの構造とライブラリを提供しており、まったく使用しなくても長い道のりを歩むことができます。変異を回避することは、Clojureのプログラミングスタイルで圧倒的に好まれています。
Clojureはすべて不変データに関するものです
Clojureのは、についてです管理する(すなわち、変異ポイントを制御することにより、可変状態をRef
よ、Atom
よ、Agent
よ、とVar
秒)。もちろん、相互運用機能を介して使用するJavaコードは自由に実行できます。
しかし、def右を使用して変数を簡単に再定義できますか?
Var
(たとえば、ローカル変数ではなく)を別の値にバインドすることを意味している場合は、そうです。実際、Varsと地球環境で述べたように、Var
sはClojureの4つの「参照タイプ」の1つとして具体的に含まれています(ただし、主に動的 Var
s を参照していると言います)。
Lispsには、REPLを介してインタラクティブで探索的なプログラミングアクティビティを実行する長い歴史があります。多くの場合、これには新しい変数と関数の定義、および古い変数と関数の再定義が含まれます。ただし、REPLの外では、def
aを表すことVar
は不適切な形式と見なされます。
たとえば、Rubyでは、変数に複数の代入を実行して、その値を構築できます。
severity = :mild error_message = "OH GOD! IT'S A DISASTER! WE'RE " if severity == :mild error_message = error_message + "MILDLY INCONVENIENCED!" else error_message = error_message + "DOOOOOOOMED!" end
Clojureでも同じようなことをしたくなるかもしれません。
(def severity :mild) (def error-message "OH GOD! IT'S A DISASTER! WE'RE ") (if (= severity :mild) (def error-message (str error-message "MILDLY INCONVENIENCED!")) (def error-message (str error-message "DOOOOOOOMED!")))
ただし、このような名前に関連付けられている値を変更すると、名前に関連付けられている値やその値が変更された理由を知ることが難しくなるため、プログラムの動作を理解するのが難しくなります。Clojureには、変更に対処するための一連のツールがあります。これについては、第10章で説明します。Clojureを学習すると、名前と値の関連付けを変更する必要がほとんどなくなります。上記のコードを作成する方法の1つを次に示します。
(defn error-message [severity] (str "OH GOD! IT'S A DISASTER! WE'RE " (if (= severity :mild) "MILDLY INCONVENIENCED!" "DOOOOOOOMED!"))) (error-message :mild) ; => "OH GOD! IT'S A DISASTER! WE'RE MILDLY INCONVENIENCED!"