コードクォートの概要
コードクォート(= code quotations)は、F#コードを表す抽象構文木を生成するための機能です。
コードクォートを利用することによって、F#のコード生成や、F#のコードから他の言語のコードを生成することが可能となります。
コードクォート式
引用符で囲まれた式(= コードクォート式)は、プログラムの一部としてコンパイルされるのではなく、F#の式を表すオブジェクトにコンパイルされる で区切られたF#式です。コードクォート式は、「型情報付き」または「型情報なし」のいずれかの方法でマークすることができます。型情報を含める場合は、" <@ ~ @> " を使用してコードクォート式を区切ります。
型情報が必要ない場合には、" <@@ ~ @@> " を使用してコードクォート式を区切ります。
また、コードクォート式を利用するためには、Microsoft.FSharp.Quotations 名前空間を open する必要があります。
次のコードは、型付きコードクォート式と型なしコードクォート式の簡単なサンプルになります。
open Microsoft.FSharp.Quotations
open FSharp.Quotations.Evaluator
let expr0 : Expr<int> = <@ 1 + 1 @> // 型付きコードクォート式は Expr<'a>型
let expr1 : Expr = <@@ 1 + 1 @@> // 型なしードクォート式は Expr型
printfn "%d" (expr0.Evaluate()) // output: 2
printfn "%A" (expr1.EvaluateUntyped()) // output: 2
コードクォート式はそのままでは処理の内容を実行できないため、FSharp.Quotations.Evaluator などのライブラリを利用します。今回利用したFSharp.Quotations.Evaluatorライブラリでは、Expr<'a>型の場合にEvaluate()を、Expr型の場合にEvaluateUntyped()を利用することでコードクォート式の中身を実行することが可能です。
コードクォート式には完全な式を含める必要があります。例えば、let束縛を利用する場合は、let束縛された名前の定義と、その束縛を使用する追加の式の両方が必要です。そのため、以下のコードクォート式は無効となります。
// 以下はエラー
<@ let f x = x + 1 @>
以下のようにすることで、有効な表現となります。
// 有効な表現(1): in句の利用
<@ let f x = x + 1 in f 20 @>
// 有効な表現(2): 複数行で記述
<@
let f x = x + 1
f 20
@>
スプライシング演算子
スプライシングを使用するとリテラルコードのコードクォート式をプログラムで作成した式や別のコードクォート式から作成した式と組み合わせることができます。スプライシングをするためには、%演算子 か %%演算子を利用します。これら2つを指してスプライシング演算子と呼びます。%演算子を利用することで、型付きコードクォート式を挿入することができます。また、%%演算子を利用することで、型なしコードクォート式を挿入することも可能です。
次の例はスプライシング演算子の簡単な例となります。
// %演算子の例
let expr0 = <@ 2 @>
let expr1 = <@ 1 + %expr0 @>
printfn "%d" (expr1.Evaluate()) // output: 3
// %%演算子の例
let expr0 = <@@ 10 @@>
let expr1 = <@@ 5 + %%expr0 @@>
printfn "%A" (expr1.EvaluateUntyped()) // output: 15
文章だけを読むと、なんだか難しそうな内容でしたが、実コードを見てみると何てことはない内容ですね。
この記事ではコードクォート式の概要のみを紹介し、実際に使う場面については別の機会に紹介しようと思います。まだ、このコードクォート式のうま味がわからないと思いますが、現時点では「コードクォート式っていう機能があるんだぁ」くらいの認識で問題ありません。
それでも気になる方は、ググって調べてみると良いと思います。