Hatena::Grouphaskell

猫とC#について書く代わりにHaskellとF#について書くmatarilloの日記 このページをアンテナに追加 RSSフィード

2012-07-30

C#よりF#が向いている領域って?

| 14:12 | C#よりF#が向いている領域って? - 猫とC#について書く代わりにHaskellとF#について書くmatarilloの日記 のブックマークコメント

Stack Overflowに質問されていた、「In what areas might the use of F# be more appropriate than C#?」の回答を翻訳してみた。

simon cousinsの回答

私は、とあるエネルギー会社向けに、発電所のポートフォリオに関する国の発電スケジュールと取引ポジションとのバランスをとるためのアプリケーションを書きました。クライアントおよびサーバーコンポーネントはC#でしたが、計算エンジンはF#で書かれています。

F#はこのアプリケーションの心臓部の複雑さに対処するために使用したのですが、このことは明らかに、エンタープライズ・ソフトウェアにおけるこの言語のスイートスポットを示しています。すなわち、大規模なデータセットのアルゴリズム的に複雑な分析です。私の経験は非常に肯定的なものでした。具体例を示します:

測定単位。私が働く業界には、いろいろな単位が散らばっています。私が実装した方程式(多くの場合、幾何学的な性質の方程式)は、時間や電力やエネルギーの単位を扱っています。型システムが、関数の入出力における単位の正確さを検証することで、コードをテストしたり、読み取って理解したりすることの両面において、巨大な時間の節約になります。それ以前のシステムで生じやすかった種別のエラー全体を根絶したのです。

探索プログラミング。スクリプトファイルとREPL(F#インタラクティブ)での作業では、実装にコミットする前に、編集→コンパイル→実行→テストの伝統的なループよりも効果的に解空間を探索することができました。それは、プログラマが問題点や設計上の緊張点を見つけるための非常に自然な方法です。

ユニットテスト。副作用のない関数やイミュータブルなデータ構造を使って書かれたコードはテストしやすいものです。すべてをややこしくしてしまう、順序依存の複雑な相互作用も、モックが必要になるような大量の依存関係も、どちらもありません。

相互運用性。私は計算エンジンへのインターフェイスをC#で定義し、計算自体はF#で実装しました。計算エンジンは、相互運用性についてはまったく心配せずに、計算エンジンを必要とするC#のモジュールに後から注入することができました。シームレスです。C#プログラマは何も知っておく必要がありません。

コードの削減。計算エンジンに供給されるデータの多くは、ベクトルと行列の形でした。高階関数は、最小の手間、最小限のコードでこれらを扱います。朝飯前です。美しい。

バグの欠如。関数型プログラミングは奇妙に感じることがあります。私がアルゴリズムに取り組んでいるときには、コードが型チェッカーを通過するように頑張らないといけないかもしれませんが、一旦型チェッカーを通してしまえば、それで終わりです。コードは動きます。基本的には2択なのです。コードがコンパイルを通らないか、コードが正しいかです。奇妙なエッジケースのエラーは最小化されます。ビジネスロジック以外のコードはエッジケースのエラーを導入しがちですが、そのようなコードは再帰高階関数によって多くが取り除かれます。

並列処理。実装の結果が関数的に純粋であることは、ベクトルデータの処理に固有の並列性を利用するのにうってつけです。NET 4が出た今は、私が次に進むべき場所は多分ここでしょう。

Tomas Petricekの回答

Microsoft Researchでインターンシップに参加していたとき、(F#自身で記述された)F#のVisual Studio IntelliSenseに関して何か所か仕事をしました。以前のC#プロジェクトですでにIntelliSenseについての経験がありましたので、両者を比較できると思います。

  • Visual Studio機能拡張は相変わらずCOMベースです。ですので、あんまり素敵とは言えない(そしてまったくもって関数的でない).NETオブジェクトを扱わないといけません。ですが、C#とF#との間に大きな違いは感じませんでした(F#でもスムーズに動作します)。
  • F#でプログラムコードを表現するのに使われたデータ構造は、ほとんどが判別共用体です(そしてそれはC#では妥当な方法でサポートされていません)。そして、この手の(プログラムコードのような木構造を処理しないといけない)アプリケーションにとっては、それは大きな違いとなります。判別共用体とパターンマッチングによってコードの構造が改善されます(関連する機能を1か所にまとめておくことができます。仮想メソッドだとあちこちに散らばってしまいますが)。

以前は、F#のCodeDOMプロバイダ(こちらもF#で記述されています)についても仕事をしました。実は最初はC#で始めたのですが、後からコードをF#に変更しました。

  • CodeDOMプロバイダは.NETのオブジェクトを使って表現された構造を探索しないといけません。ですので、独自のデータ表現を考える余地はほとんどありませんでした(そしてそこがF#が力を発揮できる分野なのですが)。
  • とはいえ、この仕事を楽にするちょっとしたF#の機能はたくさんありました。とある文字列を生成しなければならなかったので、(StringBuilderを使って)文字列を組み立てるカスタム演算子をいくつか定義した上で、それらの演算子高階関数を使ってコードを実装しました(たとえば、指定した文字列をセパレータに使ってオブジェクトのリストをフォーマットするといったようなものです)。そうすることで、コードの重複を大幅に削減できました(つまらないforeachループもです)。

比較的詳細な例を2つ挙げましたが、どちらもプログラムの表現形式や式に関係するものです。もっと一般的に言えば、木構造のような複雑なデータ構造です。この分野ではF#が間違いなく良い選択肢だと思います(C#にも関数型の機能があることを踏まえても、です)。