コードクォート
Midoliy|F#プログラミング

コードクォートの概要

コードクォートの概要


 コードクォート(= 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

 文章だけを読むと、なんだか難しそうな内容でしたが、実コードを見てみると何てことはない内容ですね。
 この記事ではコードクォート式の概要のみを紹介し、実際に使う場面については別の機会に紹介しようと思います。まだ、このコードクォート式のうま味がわからないと思いますが、現時点では「コードクォート式っていう機能があるんだぁ」くらいの認識で問題ありません。
 それでも気になる方は、ググって調べてみると良いと思います。