Scalaで関数型プログラミングをする#2 純粋関数型プログラミング言語とScala

2012.12.23

純粋関数型プログラミング言語とScala

Ⅰ.はじめに

前回確認したように、関数型プログラミングを行うには、

  • 1.副作用がない(参照透過性が高い)
  • 2.言語内において関数が第一級の身分を持つ(ファーストクラスとして扱うことが可能)

という条件を満たす必要があります。
2番目の条件に関しては言語がそういった機能を持つしかないのですが、
1番目の条件については、実装次第で副作用を排除することも持つこともできます。
しかし副作用を言語の機能から一切排除した言語もあります。
それが「純粋関数型プログラミング言語」とよばれるプログラミング言語です。

Ⅱ.純粋関数型プログラミング言語

HaskellやConcurrent Cleanというのが代表的な純粋関数型言語のようです。
ここではHaskellがどういう特徴を持っているか見てみましょう。

haskell

1.最近の言語で使用できる便利な機能をサポート

高階関数や静的多相型付(ジェネリクス)、例外処理等の近年よく使用される言語でも多くのものが持つ機能をもっています。
また、Scalaと同じくパターンマッチ、カリー化やリスト内包等の特徴ある機能も持っています。

2.遅延評価が基本

評価が必要な値があるとき、実際に計算をするのは値が必要になるまで行わないことをいいます。
評価を遅らせるということは結局「必要なものしか評価しない」ということなので、
無駄な計算が発生せずに実行効率が良いということですね。
また、無限リスト(要素の配列が無限に続くリスト)を扱うこともできます。
Haskellではこの遅延評価が基本になっていますが、
Scalaの場合はlazyキーワードを使用すれば値の遅延評価が可能です。

3.一度割り当てられた変数の値は変更されることがない

Javaでいえば、変数はすべてfinal宣言されたようなものであり、Scalaでいえば変数はすべてvalになるイメージです。
Haskellでは、副作用となる「変数への代入」はありません。

4.参照透過性を壊すことなく副作用を実現するモナド

Haskellでは副作用が許可されてませんが、何かの処理を行う以上はどこかでIO処理を行わなければいけません。
例えば、コンソールに文字を表示させるだけでも標準出力を内容を変更しているわけですが、これは副作用です。
このIO処理にともなった副作用をなんとかするためにHaskellではIOモナドという仕組みを用意しています。
IOモナドは、

  • 「IO処理に伴われる副作用をプログラムから取り除く」
  • 「関数が評価される順番を指定できない純粋関数型言語において、IO処理の処理順序を指定する方法を提供する」

という2つの機能を持っています。
このIOモナドにより、Haskellでは副作用を持たずにIO処理を実現しています。
なお、モナドの詳細についてはまた次回以降。

参考:
Haskell
サルでもわかるIOモナド①-副作用の除去

Ⅲ.Scalaは純粋関数型言語ではないが

Scalaにおいて関数はファーストクラスオブジェクトとなっているので、2番目の条件は満たしています。
副作用については、Scalaはそれを許可しているので、変数の書き換えもやろうと思えば可能です。
とはいえ、副作用をなくす(少なくする)ことは保守性の向上やマルチスレッド環境での有用性に変わりはないので、
純粋関数型言語でないScalaの場合でも、関数型プログラミングは可能です。

ScalaをBetter Javaとして使いたいというのであれば、意識して関数型プログラミングにする必要はないと思います。
しかし、Scalaの言語パワーを最大限に使いたいのであれば、上記で述べたようなスタイルを守り、
純粋関数型言語を意識した関数型プログラミングを行うことが重要だと思います。

では具体的にScalaで関数型プログラミングをするにはどうしたらいいのかと自分も考えていたのですが、
今後関数型プログラミングについて学んでいくために、次のことをやっていこうと思っています。

1.概念について学ぶ

kenron
関数型プログラミングは、代数的構造や圏論といった概念にもとづいているので、
まずは圏論やモナド、関手といった概念について学んでいくことが必要ではないかと思っています。

2.scalazを使う

scalaz
関数型プログラミングの背景について学んだ後、実際にscalaで関数型プログラミングをするために
scalazを使うのがいいのではないかと思います。
scalazとはScala用のライブラリで、これを使用すると
型クラスを用いて純粋関数型データ構造を持ったプログラミングを行うことができます。

というわけで、「scalazを使って関数型プログラミングをできるようになる」のを目指していきます。
正直いって概念もscalazも(自分にとっては)めちゃくちゃハードルが高いのですが、がんばって少しずつ学んでいきます。