はじめに
現在、.NET開発者がMicrosoftのソリューションだけを使ってアプリケーションを開発する場合は、Visual Basic、C#、C++のいずれかを使用します。この3つの言語はどれも命令型プログラミングと呼ばれるプログラミングパラダイム(モデル)に基づいています。つまり、問題を解決するための手順を開発者が自ら正確に指定しなければなりません。これは、ステートメントを正しい順序で並べることによって行われますが、アプリケーションの状態を格納する変数やクラスのインスタンスなども使用します。
このプログラミングモデルは多くの状況で極めて効果的ですが(プログラミングの分野にとどまらず、家具の組み立ての説明書や料理のレシピも命令型プログラミングの一種です)、すべての操作にとって最良の方法というわけではありません。そのため、関数型プログラミングが開発されました。
関数型プログラミングは、C#などの言語より、学校で学んだ数学に似ています。しかし、関数型言語は計算にだけ役立つわけではありません。実際、C#で行う操作とまったく同じ操作を、F#などの関数型言語では行うことができます。
関数型言語で1番重要なのは、どのような種類のデータが必要で、そのデータを使って何を行う必要があるかです。さらに、関数型言語では、関数の概念がすべての基本になります。詳しくは後で説明しますが、これはつまり、状態を保持することはもはや重要でないという意味でもあります。現代における関数型プログラミング言語の例には、XSLT、LINQ、そしてもちろんLISPがあります。.NET開発者向けに新しく登場したのがF#です。
F#言語の概要
F#は当初、Microsoft Researchのリサーチプロジェクトとして始まりました。以来、成長を続け、Visual Studioに含まれる最初の関数型言語の最有力候補になっています。「関数型」と聞くと何らかの制限を受けるように感じるかもしれませんが、F#の利点はオブジェクト指向の構造をサポートすることです。また、.NET Frameworkへのフルアクセスも備えています。
C#などの言語に精通している人にとっては、最初のうち、F#には見慣れた部分とそうでない部分の両方があることでしょう。例えば、数値配列に2を掛けて出力するというコードをF#で書くと、次のようになります。
let timesTwo x = x * 2 let numbers = [1; 4; 5; 7; 12] let numbersTimesTwo = List.map timesTwo numbers printfn "Numbers = %A" numbersTimesTwo
この4行のコードは、F#における2つの重要な概念を示しています。1つは関数とリストの定義で、もう1つはList.map
などの標準関数です。もちろん、おなじみの"Hello, World"プログラムを作成する場合は、printfn
関数が大いに活躍します。
関数型言語のもう1つの典型的な例としては、関数の作成方法と使用方法があります。階乗を計算する次の例を考えてみましょう(階乗とは、2からnまでの数値の積です。例えば、5!は2*3*4*5 = 120に等しくなります)。
let rec factorial n = if (n = 0) then 1 else (n * factorial(n-1)) let x = 5 let f = factorial(x) printfn "%d! = %d" x f
関数型言語では、通常のループの代わりに再帰を使用します。F#も例外ではありません。上のどちらのコードリストにおいても、先頭のコード行ではlet
キーワードで新しい関数を定義しています。2番目の例(すぐ上の例)では、rec
キーワードによって、関数factorial
が再帰的に使用されることが指定されます。次のリストでは、配列内で5より大きい値を見つけます。
let numbers = [1; 4; 5; 7; 12] let largeNumbers = List.filter (fun x -> x > 5) numbers printfn "Large numbers = %A" largeNumbers
List.filter
関数は関数パラメータ(fun
キーワードで定義)を受け取り、リスト内の各要素に対してこれを実行します。このコードと、C#とLINQを使ったコードを比べてみてください。
int[] numbers = { 1, 4, 5, 7, 12 }; var largeNumbers = numbers.Where(n => n > 5); foreach (int num in largeNumbers) MessageBox.Show(num.ToString());
このように、関数型プログラミングのコードは一見すると見慣れた形を取っているようですが、実際に慣れるまでには少し時間がかかります。特に、C#アプリケーションの比較的簡単なやり方と比べると、その違いがはっきりします。関数型言語は一般に、アルゴリズムの実装と、金融、統計、数学的研究などの分野で最も効果を発揮しますが、F#はさらに広い分野で利用できます。
次に、ヨーロッパ中央銀行(ECB)から米ドル(USD)とユーロの最新の為替レートを取得する次のコードを考えてみましょう。コードを使用するには、ソリューション内にSystem.Xml.dllアセンブリファイルへの参照を追加する必要があります。
let ecbXmlUri = "http://www.ecb.europa.eu/\ stats/eurofxref/eurofxref-daily.xml" let xpathNavi = System.Xml.XPath.XPathDocument(ecbXmlUri).CreateNavigator() let resolver = System.Xml.XmlNamespaceManager(xpathNavi.NameTable) let xmlNsEcb = "http://www.ecb.int/vocabulary/\ 2002-08-01/eurofxref" let xmlNsGm = "http://www.gesmes.org/xml/2002-08-01" resolver.AddNamespace("ecb", xmlNsEcb) resolver.AddNamespace("gm", xmlNsGm) let nodePath = "/gm:Envelope/ecb:Cube/ecb:Cube\ /ecb:Cube[@currency = 'USD']" let node = xpathNavi.SelectSingleNode(nodePath,resolver) let rate = node.GetAttribute("rate", "") printfn "USD to Euro exchange rate is: %s." rate
このリストから、F#アプリケーション内で.NET Frameworkを完全に利用できることが分かります。実際、F#は関数型と命令型の両方の構造をサポートするハイブリッド言語と見なすことができます。例えば上記のコードは、C#で作成したコードと非常によく似ています。
つまりF#では、クラス、オブジェクト、インターフェースがすべて使用できます。また、独自のクラスやインターフェースを作成することもできます。余談になりますが、上のリスト内のちょっと変わった構文にも注目してください。例えば、長い文字列はバックスラッシュで複数行に分割できます。