今注目されている!関数型プログラミングとは【初心者向け】
初心者向けに関数型プログラミングとは何か詳しく解説しています。企業でも採用し始めている関数型言語ですが、一体どんな特徴があり他の言語と比べてどんなメリット・デメリットがあるのか説明しています。代表的な関数型言語も覚えておきましょう。
テックアカデミーマガジンは受講者数No.1のプログラミングスクール「テックアカデミー」が運営。初心者向けにプロが解説した記事を公開中。現役エンジニアの方はこちらをご覧ください。 ※ アンケートモニター提供元:GMOリサーチ株式会社 調査期間:2021年8月12日~8月16日 調査対象:2020年8月以降にプログラミングスクールを受講した18~80歳の男女1,000名 調査手法:インターネット調査
この記事では、関数型プログラミングとは何なのか、解説しています。
関数型言語は、効率よく開発できる言語として採用している企業も増えてきています。言語の特徴やどんなメリットデメリットがあるのか理解しておきましょう。
今回は関数型プログラミングについて勉強してみよう。
田島メンター!関数型プログラミングというのは何ですか〜?
関数の組み合わせによってプログラムを構成していく手法を指して言うんだ。例を見ながら紹介していこう。
お願いします!
目次
関数型プログラミングとは
関数型プログラミングとは、解決しようとする問題に対し、その問題の性質を関数の組み合わせで記述するプログラミング手法です。
これに対し、命令型プログラミングでは、問題を解く手順をコンピュータが実行すべき命令の列として記述します。
言葉だけでは分かりづらいので、例を見ていきましょう。
種別(category)と価格(price)を持つ商品(Item)のリストから、食品(種別がFoodsのもの)の合計金額を計算するメソッドを考えます。
まずは、Javaで記述した場合の命令型プログラミングのサンプルです。
Javaのプログラム
public int totalFoodsPrice(List<Item> itemList) { int totalPrice = 0; for (int i = 0; i < itemList.size(); i++) { Item item = itemList.get(i); if (Objects.equals(item.getCategory(), "Foods")) { totalPrice += item.getPrice(); } } return totalPrice; }
この処理の中では、変数iは商品リストの何番目を処理しているか、変数totalPriceは現在計算が完了している合計金額がいくらになっているか、というプログラムの状態を表します。
変数iは、ループが行われるごとにi+という命令文によって、現在のiに1を足した値が代入されます。
変数totalPriceは、totalPrice += item.getPrice( )という命令文によって、ループ中の商品の価格を足した値が代入されます。
このように、プログラムの状態を表す変数の値を代入命令で変更していき、最終的に目的を達成することは命令型プログラミングの基本的な流れになります。
次に、Scalaを使用して同じ処理を関数型スタイルで実装した場合のサンプルです。
Scalaのプログラム
def totalFoodsPrice(itemList: List[Item]): Int = itemList match { case Nil => 0 case Item("Foods", price) :: otherItems => price + totalFoodsPrice(otherItems) case _ :: otherItems => totalFoodsPrice(otherItems) }
このメソッドは入力として商品リストを受け取り、先頭が食品であれば残りの商品リストの合計金額に価格を足し、そうでない場合は残りの商品リストの合計金額をそのまま返す、という内容になっています。
一見、馴染みが無い方には分かりづらくなったように思われるかもしれませんが、このメソッド内には変数の初期化や代入といった命令文が存在しません。現在は何番目の商品を扱っているか、現在の合計金額はいくらか、といった状態はここには現れないということです。
状態を変化させながらループさせるという手段の代わりに、すべての商品に対する繰り返し処理は同じメソッドを再帰的に呼び出すことで実現しています。
※ 再帰処理をすることが重要なのではなく、状態を扱わないということが重要で、実現方法は他にも存在します。
状態をプログラムの中で扱い、変化させていくことは、プログラムの動作を分かりづらくさせたり、テストやデバッグを困難にする原因となります。
これを避け、プログラムの状態を変化させない関数を作成し、これを組み合わせて(上記の例では再帰的に呼び出して)問題解決を行う手法が関数型プログラミングです。
ここで、変数の再代入や入出力などによってプログラムの状態が変化することを副作用と言い、副作用を持たない関数を純粋関数と呼びます。
関数型プログラミングの基本は、純粋関数の組み合わせでプログラムを作り上げることとなります。
関数型の基本的な特徴についてだね。
JavaとScalaを比較してみると、目的に対する手順が違っているのが分かりますね。
次に、関数型プログラミングにはどういったメリットやデメリットがあるのかについて見てみよう。
関数型プログラミングのメリット
プログラムの分かりやすさ
関数型プログラミングの最大のメリットは、プログラムが人間にとって分かりやすくなるという点です。
命令型で書かれたプログラムは、人間に対する分かりやすさよりコンピュータにとっての分かりやすさが優先されています。コンピュータにとって、実行中のプログラムの状態が明確であることは重要なポイントです。
しかし、人間が本来関心を持つのは実行中のプログラムの状態ではなく、プログラムに対する入力とその実行結果です。
関数型プログラミングでは、入力に対して必要な結果を導く関数を用意し、組み合わせていきます。関数の内容は実行中のプログラムの状態からは独立したものとなり、より人間の思考に近く、書く側にとっても読む側にとっても分かりやすいものとなります。
テストのしやすさ
関数型プログラミングでは、関数に対して同じ入力から等しい実行結果が得られるため、テストがしやすくなるというメリットもあります。
これは、正確には関数型プログラミングのメリットというよりは副作用を抑えるプログラムのメリットで、命令型プログラミングでも意識して設計すれば得られるメリットです。
実際、命令型プログラミングでもテストのしやすさを重視し、副作用に気を配っているという方も少なくないと思います。
ですが、関数型プログラミングでは純粋関数を宣言して組み合わせることが基本になるため、このメリットをより自然に受けることができます。
関数型プログラミングのデメリット
パフォーマンスチューニングが難しい
命令型プログラミングでは、1行ずつどういった命令をコンピュータが行なっているかが明確なので、比較的パフォーマンスチューニングが行いやすいと言えます。
これに対し、関数型プログラミングでは、コンピュータが実際に実行する1つ1つの命令を把握するのは難しく、命令型プログラミングほどチューニングは容易ではありません。また、無理にチューニングすることで、関数型としては不自然なコードになってしまう場合もあります。
誤解してはならないのは、関数型プログラミングでは実行速度が遅い、ということは決してなく、広く使われている関数型言語は多くの命令型言語と比べても遜色ない実行速度を備えています。ですが、CやC++、あるいはFORTRANが選ばれるような、限界までハードウェアの性能を引き出すことが必要な用途で関数型プログラミングを使用することは、現実的とは言えません。
もちろん、世の中の多くのソフトウェアはそこまでの性能は必要なく、開発効率やメンテナンス性の方が重要になります。このような多くの分野では、関数型プログラミングは有効な手段となります。
関数型言語とは
関数型言語とは、関数型プログラミングを行うことを推奨して設計されているプログラミング言語です。
誤解してはならない点として、
- 関数型言語でなければ関数型プログラミングが行えない
- 関数型言語では命令型のプログラミングを行うことができない
この2点は誤りです。
関数型プログラミングを実現すること自体は、多くのプログラミング言語で可能です。逆に、関数型言語と呼ばれる言語でも命令型のプログラミングを行うことができます。
ですが、一般に関数型言語と呼ばれる言語には、言語の設計段階から関数型プログラミングの実現を補助するための多くの言語機能が用意されており、それらを使って関数型プログラミングを行うことが前提となっています。「この言語機能があれば関数型言語である」という定義があるわけではありませんが、この特性によって関数型言語で作成した関数型プログラミングは非常にシンプルで自然なものとなります。
また、関数型言語にはさらに純粋関数型言語と非純粋関数型言語の2種類が存在します。
純粋関数型言語では、すべての式や関数が純粋関数のみで構成されます。一方で、実用性や既存言語との相互運用性を考慮し、副作用を持つ関数を許容する言語も多く存在し、これらは非純粋関数型言語と呼ばれます。
この2種類は、どちらかが優れているというものではなく、その言語が目指す方向性の違いによって異なっているものです。
主な関数型言語
Scala
オブジェクト指向言語と関数型言語の特性を併せ持つ、マルチパラダイムの関数型言語です。
2つの言語特性を1つの概念として統合することにより、小さなスクリプトから大きなシステムまで同じ概念で実現できるスケーラブルな言語仕様が特徴です。
Java仮想マシン(JVM)上で動作し、既存のJavaプログラムやJavaライブラリと容易に連携できることも特徴で、広く使われてきたJavaの資産を有効に活用することができます。
TwitterがScalaを大規模に採用しているほか、国内でもChatWorkやBacklogなどScalaへの移行事例が増えてきています。
Haskell
純粋関数型言語と言える言語です。
純粋関数型言語でありながら入出力のような副作用を伴う操作を実現するためにモナドという機能を持ち、その他にも多くの先進的なプログラミング機能を持っています。
その結果、言語の仕様に従うことで、「良い関数型プログラミング」となるような実装を行いやすくなっています。
Facebookにおけるスパムやマルウェア対策に使われているほか、国内ではTsuru Capital社が金融商品の高頻度取引システムで使用するなど、信頼性の求められる分野でも広く使用されています。
Erlang
エリクソン社が自社用に開発し、のちにオープンソースとして公開した関数型言語です。
同時実効性の非常に高い電話交換アプリケーションの構築を目的として設計されたという経緯もあり、仮想マシン(Erlang VM)上で大量のプロセスを実行するための並行処理プログラミングをサポートする言語機能を持っています。
近年はLINEやWhatsAppのほか、League of Legendsというゲームのチャットシステムなど、主に大量のリクエストをリアルタイムで処理する分野で採用されています。
以上、関数型プログラミングについて解説しました。
関数型言語を採用し始めている企業も増えていますが、どんな特徴を持った言語なのか知っておくと良いでしょう。
最後に、関数型言語をいくつか挙げてみたよ。
Scalaが非純粋関数型なのに対して、純粋な関数型言語というのも存在するんですね。
Haskellなどは純粋関数型言語の代表的な例になるね。関数型を使うことによってどのような利点があるのかを考えながらその特徴を捉えていこう。
分かりました。ありがとうございます!
オンラインのプログラミングスクールTechAcademyでは、Scalaオンライン講座を開催しています。
Scalaを使ってWebアプリケーションを開発することができます。
現役エンジニアがパーソナルメンターとして受講生に1人ずつつき、マンツーマンのメンタリングで学習をサポートし、最短4週間で習得することが可能です。
また、現役エンジニアから学べる無料のプログラミング体験会も実施しているので、ぜひ参加してみてください。
この記事を監修してくれた方
金澤秀知(かなざわひでとも) 開発実績:大量の調査画像を分類するシステムの開発、業務用の人材管理アプリケーション開発、アクティブ・ラーニング用スマートフォンアプリ開発など 主にJava・Scalaを用いたサーバサイドプログラミングを中心としつつ、AWS・Azure・Firebaseなどのクラウドプラットフォームを使ったアーキテクチャ設計も行ってきた。開発にともなう課題として、自動テストを用いたソフトウェアの品質向上にも取り組んでいる。現在は高知県に住み、リモートワークを使った働き方を実践中。 |