関数型プログラミングの大きな特徴の1つとしての考え方です。
ある処理においてメソッドは与えられた引数を元に計算を行い、値を返すことだけでなければならない。
副作用の処理として、例えば「変数の値の変更」や「入出力(I/O)」が挙げられます。
そしてそれは、オブジェクト指向と関数型の合いの子でもある「Scala」も持っている性質です。
どうもリリ@関数型言語初心者 です。
Scalaを勉強しているもののJavaしか触ったことのない私にはいまいち飲み込めない関数型の考え方。
import文の書きかたひとつにしても(別名をつけることができるなど)多様な書き方ができたり、
「型推論」やメソッドとフィールドの定義をカプセル化した「trait」に、関数を引数として渡したり、戻り値として返す「高階関数」…
正直色々とわけがわからないことばかりです。
…と泣きごとを言っていても最近はウソかホントかScalaを採用しているプロジェクトが多いという話もあるので
時代に取り残されないようちょっとずつ理解できたと思われる内容を書いていければと思います。
さて!前置きが長くなりましたが、今回は「メソッドは副作用を持っていてはならない」という思想を実現するにあたって必要な要素である
オブジェクトのimutable(変更不能化)についてまとめます。
■「変更可能(mutable)と「変更不能(immutable)」
まずは下記のコードを見てみてください
Listnum = new ArrayList ();
num.add("one");
num.add("two");
num.add("three");
上記のようにJavaのList(java.util.List)では、定義したリストの要素を追加したり削除したりと自由に変更できます。
つまりリストは「変更可能(mutable)」なのです。
もちろん、Scalaでも変更可能なリストを定義したパッケージ(scala.collection.mutable)も用意されていますが
Scalaでは基本的に変更不能なリスト側のパッケージ(scala.collection.immutable)を使用します。
コードはこんな感じ
val snum = List("one", "two", "three")
これでListの初期化が行えます。
しかし、num はimmutable のため、要素の追加ができないんです。
…どうしましょう。
Listなどのコレクションは常に変更可能という考えを持っていた私にとってこれは想像外の考え方です。
■なぜimmutable?
コレクションの使用用途としては繰り返し処理がつきものです。
関数型言語のコレクションでは「繰り返し処理」と「要素に対する処理」を切り離して考えるのが普通のようです。
Javaにおいてはコレクションをfor文で繰り返すコードが一般的ですが、同じような処理を何度も書くとコードが長くなり修正漏れの危険性が増すというデメリットが出てきます。
その点、immutableなコレクションであるScalaのリストは、一度定義されたらそのコレクションの要素は不変なので中身が保証されています。
■それで「副作用を持たないようにする」とimmutableの関係って?
前述の通り、immutableなコレクションを定義することによって繰り返し行う処理に使用するコレクションの要素は不変であることが保証されています。
コレクションに変化があるときは必ず新しいコレクションが生成されるため
コレクションの要素に対する処理を行う段階で変更が加えられることもありません。
Javaのコレクションが「処理を行っていく中で要素を作る」
のなら
Scalaはコレクションを「最初に定義する」
という処理の流れを念頭において設計する必要があるということがわかりました。