第5章. 不変性についての詳細
この作品はAIを使って翻訳されている。ご意見、ご感想をお待ちしている:translation-feedback@oreilly.com
ここまで、FPにとって不変性がいかに重要であるかを見てきた。この章では、不変性を促進するいくつかのテクニックに焦点を当てる。再帰的、高階関数、モノイドと高階関数の組み合わせなどである。この章では、モノイドとフォールドと呼ばれる、一見異なるが実際には非常によく似たタイプの関数を表す新しいパターンも紹介する。この章ではまず、可変性と不変性の変数について説明する。
注
不変性は関数型コードにおける重要な特性である。プログラムの可変性が低ければ低いほど、プログラマがプログラムを書く際に念頭に置かなければならないことは少なくなる。多くのプログラマ・エラーは、プログラマが一度に大量の変化する細部を頭に入れておくことができないことに起因している。変化する状態は、私たちが追跡し管理しなければならない複雑さを引き起こす。
可変性変数と不変性変数
ほとんどのプログラミング言語では、 変数を作成し、その値をセットして、後で変更することができる。これを許さない例としては、Haskellがある。セットした後に変更できる変数を可変性変数と呼ぶ。
注
命令型プログラミングやオブジェクト指向プログラミングでは、可変性変数はどこにでもある。これまで述べてきたように、FPではミュータブル変数を避ける。
不変性は、並行処理や並列処理を行う際に特に価値があるが、これについては次の章で説明する。とりあえず、不変性を実現する方法についてもう少し詳しく見ていこう。変数を変更する代わりに、新しい値で変数をコピーすることがいかに便利であるかは、すでに見たとおりである:
Scala
caseclassUser(firstName:String,age:Int)valuser=User("Peter",34)
そして翌年には、それがある:
user.copy("Peter",age=35)
元のインスタンスの変数age を変更するだけではなく、User の新しいインスタンスが作成される。コピーは不変性を実装する方法の一部である。
注
関数型プログラミングでは、オブジェクト内の変数を変更するよりも、オブジェクトをコピーすることを好む。
不変性を実現するもうひとつの方法は、 再帰的である。これを見てみよう。
再帰的
再帰性とは、関数の特性のひとつである。簡単に言えば、関数本体のどこかで自分自身を呼び出している場合、その関数は再帰的である。考えてみれば、これは奇妙なことだ。f がまだ完全に定義されていないのに、f がf を呼び出すことができるだろうか?無限ループを期待するかもしれない。確かに、再帰関数の定義が悪ければ無限ループになる可能性はある。この関数を挙げないわけにはいかない:
deff():returnf()
これは最も単純な再帰関数である。この関数を呼び出すとどうなるだろうか?第1章では、再帰的関数の例として次のようなものがあった。
Java
voidf(inti){if(i>99){return;}else{System.out.println(i)returnf(i+1)}}
この例では、状態は変化していない。
もっと本質的なことを考えてみよう。
リンクされたリストの例
ここでは、、一般的な可変性の方法で書かれたコードを見て、関数的アプローチを使ってそれをすべて不変性にする方法を見ていく。次のコードはリンクリストを定義し、それに ...