はじめに
言語指向プログラミングの第2弾として、今回は外部DSLにて書かれた具体的表現を読み込んでF#に変換する技術について解説します。
アクティブパターン
アクティブパターンとはある値に複数の表現方法(フォーム)を与えることで、XMLなどの型付けされていない異種混在なデータに対しても、パターンマッチを可能にする技術です。
構文中のバナナクリップ(||)に囲まれた各部分をアクティブパターン識別子と呼びます。パターンマッチなどでアクティブパターンを使用する場合には、このアクティブパターン識別子経由で呼び出します。
アクティブパターン識別子は、アクティブパターンに引数として渡される入力データ用パーティションに対する名前のようなものです。
-------------------------------------------- //シングルケース (|アクティブパターン識別子|) [引数] = 式 //マルチケース (|アクティブパターン識別子1|アクティブパターン識別子2|..|) [引数] = 式 -------------------------------------------- //パターンマッチ基本使用方法 let パターンマッチ名 引数 = match 引数 with | パターン1(※1) -> 式 | パターン2 -> 式 --------------------------------------------
パターンマッチにおいて、パターンが識別子で2文字以上で大文字で始まる場合は(※1)、コンパイラがアクティブパターンなどのパターン識別子との照合を試みます。一致する識別子が見つからない場合は次のパターンが入力値(引数)と比較されます。
比較において一致が発見された場合、アクティブパターンの式部分に記述された該当する変換作業が行われ、その結果が戻され、それからパターンマッチが行われます。つまり、アクティブパターンの各アクティブパターン識別子を関数のように機能させ、その結果をパターンマッチングの一部として使用できます。これは言い方を変えれば、ある値をアクティブパターン(関数)で変換してからパターンマッチングを行う補助関数とも言えるでしょう。
アクティブパターンにはシングルケースとマルチケースの2種類があります。シングルケースとは、アクティブパターン識別子が1つしかないもので、引数として渡された入力データをあるたった1つの方法で変換します。一方、マルチケースとは、アクティブパターン識別子が複数あり、入力される値によって変換パターンが異なります。
いずれの場合にもパターンマッチからアクティブパターンを呼んで使用する際には、ちょうど関数を呼ぶようにアクティブパターンを呼び、アクティブパターンの式の部分に記述される変換作業を行います。
open System.Drawing //シングルケースアクティブパターン let (|TestRGB|) (n : System.Drawing.Color) = //※2 (n.R, n.G, n.B ) //パターンマッチ let printRGB (n: System.Drawing.Color) = match n with |TestRGB(r, g, b) -> printfn " Red: %d Green: %d Blue: %d" r g b //※1 printRGB Color.Red;;
▼
Red: 255 Green: 0 Blue: 0 val ( |TestRGB| ) : Color -> byte * byte * byte val printRGB : Color -> unit
上記リストはシングルケースアクティブパターンの例です。パターンマッチのパターンとして定義されたTestRGBは、シングルケースアクティブパターンとして、唯一の式(変換作業)を実行し、System.Drawing.Color型の入力データを引数としてシングルケースアクティブパターン(※2)に渡し、処理をしてからパターンマッチ(※1)を行っています。
引数nを渡されたシングルケースアクティブパターンTestRGBは、いかなるSystem.Drawing.Color型の引数を受けた場合にも、その(n.R、n.G、n.B)の組を返します。