なぜC#ではなくF#を使いたいのか : 構造化分析と関数型プログラミング #fsharp
この記事は F# Advent Calendar 2017 - Qiita の 11 日目の記事です。
本記事では、なぜ自分がC#ではなくF#を使いたいのかを記したいと思います。
この記事で言いたいこと
- コンピュータシステムの本質とは入力データを出力データに変換することだと思っているので、そのままシンプルにデータフローでモデリングしたいよ
- 関数型プログラミングとDFDは相性が良いよ
- DFDのデータ・ディクショナリは代数的データ型(F#ではレコードや判別共用体)でそのままコードに落とし込めるよ
- だからC#よりもF#を使いたいよ
コンピュータシステムとは何をするものか
我々ソフトウェアエンジニアは入力データを出力データへ変換するためにソフトウェアを作っています。
入力データは、UI越しのユーザ入力かもしれないし、ファイルから読み取るのかもしれないし、ネットワーク越しにくるのかもしれないし、OSのタイマーが一定間隔で発行するイベントかもしれません。
出力データは、UIでのユーザへの情報提示かもしれないし、ファイル、ネットワークなどへ送り出すのかもしれません。
つまり、ソフトウェアシステムとは、入力データを出力データに変換するプロセスです。そして、そのためのモデリングツールとして、何十年も前からあるのが構造化分析とデータフローダイアグラム(DFD)[1]です。
なお、近年では、リアクティブプログラミング用のライブラリ(Rxなど)によって、時系列の一連の入力データを、これまた時系列の出力データに変換するプロセスも宣言的に書けるようになってきています[2][3]。
関数型モデリングツールとしてのDFD
オブジェクト指向分析におけるモデリングツールとしてUMLがあります。では、関数型プログラミングにおいてモデリングに使うツールは何でしょうか。 関数型プログラミングでは、基本的に副作用のない関数を組み合わせてアプリケーションを作成します。副作用のない関数は入力を出力に変換するものなのでDFDと相性がよく、関数型プログラミング言語ではDFDをそのままコードに落とし込む事ができます。
データ・ディクショナリと代数的データ型
構造化分析とシステム仕様[1] によると、DFDでフロー中を流れるデータはデータ・ディクショナリに定義されます。そして、個々のデータは、要素の繰り返し・連結・選択によって定義されます。
名前 = 姓 and 名 分類 = 幼児 or 子供 or 大人
この構造は、そのまま代数的データ型(F#では判別共用体やレコード)で表す事ができます。
type 名前 = { 姓 : string; 名 : string } type 分類 = 幼児 | 子供 | 大人
DFDをコードに落とし込む際の、C#と比較したF#の利点
以前の記事 なぜC#よりもF#なのか 2017 #fsharp - p_tan's blog でもC#とF#を比較していますが、DFDをコードに落とし込むという観点からC#とF#を比較すると、F#には以下のようなメリットがあります
- ユーザ定義型を作成するのが簡単
- 粒度の細かな関数を組み合わせて大きな関数を作りやすい。すなわち、DFDのプロセスの分解と、関数の粒度を合わせやすい
- 上記の代数的データ型によって、データ・ディクショナリのコード化が楽
- パターンマッチでの網羅性判定により、機能追加時の実装忘れなども警告が出る
まとめ
関数型プログラミングは、「普通の」アプリケーションの開発をきっとシンプルにしてくれます。
業務でF#つかいたいなぁ・・・。
参考書籍
- [1]構造化分析とシステム仕様<新装版> : DFDの古典
- [2] 関数型リアクティブプログラミング : 関数型リアクティブプログラミングはDFDの実装方法の一つ
- [3] Dataflow and Reactive Programming Systems : データフローとリアクティブプログラミングについてまとめられている