コード クォートCode Quotations

注意

API リファレンスのリンクをクリックすると MSDN に移動します。The API reference link will take you to MSDN. docs.microsoft.com API リファレンスは完全ではありません。The docs.microsoft.com API reference is not complete.

このトピックで説明コード クォート、言語機能を生成し、プログラムで F# コード式を処理することができます。This topic describes code quotations, a language feature that enables you to generate and work with F# code expressions programmatically. この機能を使用して、F# コードを表す抽象構文ツリーを生成できます。This feature lets you generate an abstract syntax tree that represents F# code. 次に、アプリケーションのニーズに応じて、抽象構文ツリーを走査して処理できます。The abstract syntax tree can then be traversed and processed according to the needs of your application. たとえば、F# コードを生成または他の言語でコードを生成するツリーを使用できます。For example, you can use the tree to generate F# code or generate code in some other language.

引用符で囲まれた式Quoted Expressions

A式を引用符で囲まれたF# 式では、プログラムの一部としてコンパイルされていない方法で区切られますが、代わりに、F# の式を表すオブジェクトにコンパイルするコードです。A quoted expression is an F# expression in your code that is delimited in such a way that it is not compiled as part of your program, but instead is compiled into an object that represents an F# expression. 引用符で囲まれた式は、型情報を持つか、型情報のない2つの方法のいずれかでマークできます。You can mark a quoted expression in one of two ways: either with type information or without type information. 型情報を含める場合は、記号<@@>を使用して、引用符で囲まれた式を区切ります。If you want to include type information, you use the symbols <@ and @> to delimit the quoted expression. 型情報が不要な場合は、と<@@ @@>の記号を使用します。If you do not need type information, you use the symbols <@@ and @@>. 次のコードは、型指定された型指定のない引用符を示しています。The following code shows typed and untyped quotations.

open Microsoft.FSharp.Quotations
// A typed code quotation.
let expr : Expr<int> = <@ 1 + 1 @>
// An untyped code quotation.
let expr2 : Expr = <@@ 1 + 1 @@>

型情報を含めないと、大きな式ツリーを走査する方が高速になります。Traversing a large expression tree is faster if you do not include type information. 型指定されたシンボルを使用した引用符で囲まれた式の結果の型がExpr<'T>、型パラメーターが F# コンパイラの型推論アルゴリズムによって決定される式の型。The resulting type of an expression quoted with the typed symbols is Expr<'T>, where the type parameter has the type of the expression as determined by the F# compiler's type inference algorithm. 型情報を含まないコード引用符を使用する場合、引用符で囲まれた式の型は非ジェネリック型のExprになります。When you use code quotations without type information, the type of the quoted expression is the non-generic type Expr. 型指定されたクラスでRawプロパティExprを呼び出して、型Expr指定のないオブジェクトを取得できます。You can call the Raw property on the typed Expr class to obtain the untyped Expr object.

さまざまな F# の式オブジェクトでプログラムを生成するための静的メソッドがある、Exprクラスを使用せずに引用式。There are a variety of static methods that allow you to generate F# expression objects programmatically in the Expr class without using quoted expressions.

コード引用符には完全な式を含める必要があることに注意してください。Note that a code quotation must include a complete expression. letたとえば、バインドの場合、バインドされた名前の定義とバインドを使用する追加の式の両方が必要です。For a let binding, for example, you need both the definition of the bound name and an additional expression that uses the binding. Verbose 構文では、これはinキーワードに続く式です。In verbose syntax, this is an expression that follows the in keyword. モジュールの最上位レベルでは、これはモジュール内の次の式にすぎませんが、引用符で囲まれている必要があります。At the top-level in a module, this is just the next expression in the module, but in a quotation, it is explicitly required.

したがって、次の式は無効です。Therefore, the following expression is not valid.

// Not valid:
// <@ let f x = x + 1 @>

ただし、次の式は有効です。But the following expressions are valid.

// Valid:
<@ let f x = x + 10 in f 20 @>
// Valid:
<@
    let f x = x + 10
    f 20
@>

見積もりをF#評価するには、 F#見積もりエバリュエーターを使用する必要があります。To evaluate F# quotations, you must use the F# Quotation Evaluator. 式オブジェクトの評価と実行F#のサポートを提供します。It provides support for evaluating and executing F# expression objects.

Expr 型Expr Type

インスタンス、Expr型が F# の式を表します。An instance of the Expr type represents an F# expression. ジェネリックと非ジェネリックExpr型が F# ライブラリのドキュメントに記載されています。Both the generic and the non-generic Expr types are documented in the F# library documentation. 詳細については、「 Fsharp.core 名前空間引用クラス」を参照してください。For more information, see Microsoft.FSharp.Quotations Namespace and Quotations.Expr Class.

スプライス演算子Splicing Operators

スプライスを使用すると、リテラルコードの引用符を、プログラムまたは別のコード引用符から作成した式と組み合わせることができます。Splicing enables you to combine literal code quotations with expressions that you have created programmatically or from another code quotation. %%%演算子を使用すると、コード クォートに F# の式オブジェクトを追加します。The % and %% operators enable you to add an F# expression object into a code quotation. 型指定さ%れた式オブジェクトを型指定された引用符に挿入するに%%は、演算子を使用します。型指定されていない式オブジェクトを型指定された引用符に挿入するには、演算子を使用します。You use the % operator to insert a typed expression object into a typed quotation; you use the %% operator to insert an untyped expression object into an untyped quotation. どちらの演算子も、単項前置演算子です。Both operators are unary prefix operators. このためexpr 、が型の型Expr指定されていない式である場合、次のコードは有効です。Thus if expr is an untyped expression of type Expr, the following code is valid.

<@@ 1 + %%expr @@>

また、 exprが型の型Expr<int>指定された引用符である場合、次のコードが有効です。And if expr is a typed quotation of type Expr<int>, the following code is valid.

<@ 1 + %expr @>

Example

説明Description

次の例では、式オブジェクトに F# コードを配置し、式を表す F# コードを印刷するコード クォートの使用を示します。The following example illustrates the use of code quotations to put F# code into an expression object and then print the F# code that represents the expression. 関数printlnが定義されている再帰関数を格納しているprintF# の式オブジェクトを表示する (型のExpr) を見やすい形式でします。A function println is defined that contains a recursive function print that displays an F# expression object (of type Expr) in a friendly format. Fsharp.coreおよびfsharp.coreモジュールには、式オブジェクトの分析に使用できるアクティブなパターンがいくつかありますが、これらはいくつか存在します。There are several active patterns in the Microsoft.FSharp.Quotations.Patterns and Microsoft.FSharp.Quotations.DerivedPatterns modules that can be used to analyze expression objects. この例では、F# の式が表示されるすべてのパターンは含まれません。This example does not include all the possible patterns that might appear in an F# expression. 認識されていないパターンは、ワイルドカード_パターン () との一致をToStringトリガーし、メソッドを使用Exprして表示します。このメソッドを使用すると、一致式に追加するアクティブパターンを知ることができます。Any unrecognized pattern triggers a match to the wildcard pattern (_) and is rendered by using the ToString method, which, on the Expr type, lets you know the active pattern to add to your match expression.

コードCode

module Print
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
open Microsoft.FSharp.Quotations.DerivedPatterns

let println expr =
    let rec print expr =
        match expr with
        | Application(expr1, expr2) ->
            // Function application.
            print expr1
            printf " "
            print expr2
        | SpecificCall <@@ (+) @@> (_, _, exprList) ->
            // Matches a call to (+). Must appear before Call pattern.
            print exprList.Head
            printf " + "
            print exprList.Tail.Head
        | Call(exprOpt, methodInfo, exprList) ->
            // Method or module function call.
            match exprOpt with
            | Some expr -> print expr
            | None -> printf "%s" methodInfo.DeclaringType.Name
            printf ".%s(" methodInfo.Name
            if (exprList.IsEmpty) then printf ")" else
            print exprList.Head
            for expr in exprList.Tail do
                printf ","
                print expr
            printf ")"
        | Int32(n) ->
            printf "%d" n
        | Lambda(param, body) ->
            // Lambda expression.
            printf "fun (%s:%s) -> " param.Name (param.Type.ToString())
            print body
        | Let(var, expr1, expr2) ->
            // Let binding.
            if (var.IsMutable) then
                printf "let mutable %s = " var.Name
            else
                printf "let %s = " var.Name
            print expr1
            printf " in "
            print expr2
        | PropertyGet(_, propOrValInfo, _) ->
            printf "%s" propOrValInfo.Name
        | String(str) ->
            printf "%s" str
        | Value(value, typ) ->
            printf "%s" (value.ToString())
        | Var(var) ->
            printf "%s" var.Name
        | _ -> printf "%s" (expr.ToString())
    print expr
    printfn ""


let a = 2

// exprLambda has type "(int -> int)".
let exprLambda = <@ fun x -> x + 1 @>
// exprCall has type unit.
let exprCall = <@ a + 1 @>

println exprLambda
println exprCall
println <@@ let f x = x + 10 in f 10 @@>

出力Output

fun (x:System.Int32) -> x + 1
a + 1
let f = fun (x:System.Int32) -> x + 10 in f 10

Example

説明Description

また、 Exprshape モジュール内の3つのアクティブパターンを使用して、アクティブなパターンが少数の式ツリーを走査することもできます。You can also use the three active patterns in the ExprShape module to traverse expression trees with fewer active patterns. これらのアクティブなパターンは、ツリーを走査するときに、ほとんどのノードの情報をすべて必要としない場合に便利です。These active patterns can be useful when you want to traverse a tree but you do not need all the information in most of the nodes. これらのパターンを使用する場合は次の 3 つのパターンのいずれかの任意の F# の式と一致する:ShapeVar式が、変数の場合ShapeLambda場合は、式はラムダ式、またはShapeCombination式が何である場合。When you use these patterns, any F# expression matches one of the following three patterns: ShapeVar if the expression is a variable, ShapeLambda if the expression is a lambda expression, or ShapeCombination if the expression is anything else. 前のコード例のようにアクティブ パターンを使用して式ツリーを走査する場合はすべて可能な F# 式の型を処理するために多くのより多くのパターンを使用する必要が、コードが複雑になります。If you traverse an expression tree by using the active patterns as in the previous code example, you have to use many more patterns to handle all possible F# expression types, and your code will be more complex. 詳細については、「 Exprshape. スナップショット||」を参照してください。For more information, see ExprShape.ShapeVar|ShapeLambda|ShapeCombination Active Pattern.

次のコード例は、より複雑なトラバーサルの基礎として使用できます。The following code example can be used as a basis for more complex traversals. このコードでは、関数呼び出しaddを含む式に対して式ツリーが作成されます。In this code, an expression tree is created for an expression that involves a function call, add. 特定の呼び出しのアクティブパターンは、式ツリー内のaddへの呼び出しを検出するために使用されます。The SpecificCall active pattern is used to detect any call to add in the expression tree. このアクティブパターンは、呼び出しの引数をexprList値に割り当てます。This active pattern assigns the arguments of the call to the exprList value. この場合は、2つしか存在しないため、これらの関数は引数に対して再帰的に呼び出されます。In this case, there are only two, so these are pulled out and the function is called recursively on the arguments. 結果は、スプライス演算子 ( mul %%) を使用したへの呼び出しを表すコード引用符に挿入されます。The results are inserted into a code quotation that represents a call to mul by using the splice operator (%%). 前の例の関数は、結果を表示するために使用されます。printlnThe println function from the previous example is used to display the results.

もう一方のアクティブパターン分岐のコードは同じ式ツリーを再生成するだけなので、結果として得らaddれるmul式の変更はからに変更されるだけです。The code in the other active pattern branches just regenerates the same expression tree, so the only change in the resulting expression is the change from add to mul.

コードCode

module Module1
open Print
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.DerivedPatterns
open Microsoft.FSharp.Quotations.ExprShape

let add x y = x + y
let mul x y = x * y

let rec substituteExpr expression =
    match expression with
    | SpecificCall <@@ add @@> (_, _, exprList) ->
        let lhs = substituteExpr exprList.Head
        let rhs = substituteExpr exprList.Tail.Head
        <@@ mul %%lhs %%rhs @@>
    | ShapeVar var -> Expr.Var var
    | ShapeLambda (var, expr) -> Expr.Lambda (var, substituteExpr expr)
    | ShapeCombination(shapeComboObject, exprList) ->
        RebuildShapeCombination(shapeComboObject, List.map substituteExpr exprList)

let expr1 = <@@ 1 + (add 2 (add 3 4)) @@>
println expr1
let expr2 = substituteExpr expr1
println expr2

OutputOutput

1 + Module1.add(2,Module1.add(3,4))
1 + Module1.mul(2,Module1.mul(3,4))

関連項目See also