注意:このシリーズを読む前に、前提知識として以下のシリーズを読むことをお勧めします:「関数型思考」 、 「式と構文」 、 「F#の型を理解する」。
多くの開発者にとって、新しい言語を学んだ後の次のステップは、既存のコードをその言語に移植することかもしれません。これにより、両言語の違いを実感できます。
以前に指摘したように、関数型言語は命令型言語とは大きく異なるため、命令型コードを関数型言語に直接移植することは多くの場合不可能です。たとえ粗い移植に成功したとしても、移植されたコードは関数型モデルを最大限に活用できていない可能性が高いです。
もちろん、F#はマルチパラダイム言語で、オブジェクト指向や命令型のテクニックもサポートしています。それでも、直接的な移植は一般的に、対応するF#コードを書く最良の方法ではありません。
そこで、このシリーズでは、既存のC#コードをF#に移植するさまざまなアプローチを見ていきます。
移植の洗練度レベル
以前の投稿の図を思い出してください。F#をC#と区別する4つの主要な概念があります。
- オブジェクト指向ではなく関数指向
- 文ではなく式
- ドメインモデル作成のための代数的型
- 制御フローのためのパターンマッチング
そして、その投稿とその後の投稿で説明したように、これらの側面は単に学術的なものではなく、開発者であるあなたに具体的な利点を提供します。
そこで、移植プロセスを3つの洗練度レベル(より適切な言葉がないため)に分けました。これらは、移植されたコードがこれらの利点をどの程度活用しているかを表しています。
基本レベル:直接移植
この最初のレベルでは、F#コードはC#コードの直接的な移植(可能な範囲で)です。モジュールや関数の代わりにクラスやメソッドが使われ、値は頻繁に変更されます。
中級レベル:関数型コード
次のレベルでは、F#コードが完全に関数型に再構成されています。
- クラスやメソッドはモジュールや関数に置き換えられ、値は一般的に不変です。
- 高階関数がインターフェースや継承の代わりに使われます。
- パターンマッチングが制御フローに広く使用されます。
- ループは「map」などのリスト関数や再帰に置き換えられています。
このレベルに到達する方法は2つあります。
- 1つ目は、F#に基本的な直接移植を行い、そのF#コードをリファクタリングする方法です。
- 2つ目は、既存の命令型コードをC#内で関数型コードに変換し、その後で関数型C#コードを関数型F#コードに移植する方法です!
2つ目の選択肢は面倒に見えるかもしれませんが、実際のコードではおそらくより速く、より快適です。Resharperなどのツールを使ってリファクタリングができるため速く、最終的な移植まではC#で作業できるため快適です。このアプローチはまた、難しい部分がC#からF#への実際の移植ではなく、命令型コードから関数型コードへの変換であることを明確にします!
上級レベル:型がドメインを表現
この最終レベルでは、コードが関数型であるだけでなく、設計自体が代数的型(特に判別共用体)の力を活用するように変更されています。
ドメインは型にエンコードされ、不正な状態が表現できないようになっており、正しさがコンパイル時に強制されます。 このアプローチの威力を具体的に示すには、「F#を使う理由」シリーズのショッピングカートの例と「型を使って設計する」シリーズ全体を参照してください。
このレベルはF#でのみ実現可能で、C#では実用的ではありません。
移植の図
上で説明したさまざまな移植経路を視覚化するのに役立つ図を以下に示します。
このシリーズのアプローチ
これら3つのレベルが実際にどのように機能するかを見るため、いくつかの実例に適用します:
- 最初の例は、"Uncle" Bob Martinが説明した有名な「ボウリングゲームカタ」のコードに基づいた、10ピンボウリングゲームの作成と得点計算のシンプルなシステムです。元のC#コードはクラスが1つだけで約70行のコードですが、それでも多くの重要な原則を示しています。
- 次に、この例に基づいたショッピングカートのコードを見ていきます。
- 最後の例は、Bob Martinの例に基づいた地下鉄の改札システムの状態を表すコードです。この例は、F#の判別共用体がオブジェクト指向アプローチよりも簡単に状態遷移モデルを表現できることを示しています。
しかし、詳細な例に取り掛かる前に、基本に立ち返ってコードスニペットの簡単な移植を行います。それが次の投稿のテーマになります。