計算式 (F#)
更新 : 2010 年 12 月
F# の計算式には、制御フローの構成要素とバインディングを使用してシーケンス化および結合できる計算を記述するための便利な構文が用意されています。 これらの計算式を使用すると、モナドの便利な構文が提供されます。モナドとは、関数型プログラムのデータ、制御、および副作用の管理に使用できる関数型プログラミングの機能です。
組み込みのワークフロー
シーケンス式は、非同期ワークフローと同様に、計算式の一例です。 シーケンス式の詳細については、「シーケンス」を参照してください。 非同期ワークフローの詳細については、「非同期ワークフロー」を参照してください。
一部の機能は、シーケンス式と非同期ワークフローの両方に共通しており、計算式の基本的な構文を示します。
builder-name { expression }
この構文は、特定の式が、builder-name によって指定される型の計算式であることを指定しています。 計算式は、seq や async などの組み込みのワークフローである場合や、ユーザーが定義したものである場合があります。 builder-name は、ビルダー型と呼ばれる特殊な型のインスタンスの識別子です。 ビルダー型は、計算式の断片を結合する特別な方法を定義するクラス型、つまり、式の実行方法を制御するコードです。 言い換えれば、ビルダー クラスによって、ループやバインディングなどの F# の多数の構成要素の操作をカスタマイズできます。
計算式では、一部の共通言語構成要素のために 2 つの形式を使用できます。 バリアントの構成要素を、 let! や do! などのように、特定のキーワードに ! (感嘆符) サフィックスを付けて呼び出すことができます。 これらの特殊な形式により、ビルダー クラスで定義されている特定の関数によって、これらの操作の通常の組み込み動作が置き換えられます。 これらの形式は、シーケンス式で使用される yield キーワードの yield! 形式に似ています。 詳細については、「シーケンス」を参照してください。
計算式の新しい型の作成
独自の計算式の特性を定義するには、ビルダー クラスを作成し、そのクラスで特定の特殊メソッドを定義します。 ビルダー クラスでは、次の表に示すメソッドをオプションで定義できます。
ワークフロー ビルダー クラスで使用できるメソッドを次の表に示します。
メソッド |
通常のシグネチャ |
説明 |
Bind |
M<'T> * ('T -> M<'U>) -> M<'U> |
計算式の let! および do! に対して呼び出されます。 |
Delay |
(unit -> M<'T>) -> M<'T> |
計算式を関数としてラップします。 |
Return |
'T -> M<'T> |
計算式の return に対して呼び出されます。 |
ReturnFrom |
M<'T> -> M<'T> |
計算式の return! に対して呼び出されます。 |
Run |
M<'T> -> M<'T> または M<'T> -> 'T |
計算式を実行します。 |
Combine |
M<'T> * M<'T> -> M<'T> または M<unit> * M<'T> -> M<'T> |
計算式のシーケンスに対して呼び出されます。 |
For |
seq<'T> * ('T -> M<'U>) -> M<'U> seq<'T> * ('T -> M<'U>) -> seq<M<'U>> |
計算式の for...do 式に対して呼び出されます。 |
TryFinally |
M<'T> * (unit -> unit) -> M<'T> |
計算式の try...finally 式に対して呼び出されます。 |
TryWith |
M<'T> * (exn -> M<'T>) -> M<'T> |
計算式の try...with 式に対して呼び出されます。 |
Using |
'T * ('T -> M<'U>) -> M<'U> when 'U :> IDisposable |
計算式の use バインディングに対して呼び出されます。 |
While |
(unit -> bool) * M<'T> -> M<'T> |
計算式の while...do 式に対して呼び出されます。 |
Yield |
M<'T> -> M<'T> |
計算式の yield 式に対して呼び出されます。 |
YieldFrom |
M<'T> -> M<'T> |
計算式の yield! 式に対して呼び出されます。 |
Zero |
unit -> M<'T> |
計算式内の if...then 式の空白の else 分岐に対して呼び出されます。 |
ワークフロー ビルダー クラスのメソッドの多くは M<'T> 構成要素を使用し、これを返します。通常、これは結び付けられる計算の種類を特徴付ける型で、別個に定義されます。たとえば、非同期ワークフローでは Async<'T>、シーケンス ワークフローでは Seq<'T> になります。 これらのメソッドのシグネチャは、メソッドを互いに結合したり、入れ子にしたりできるようになっています。これにより、ある構成要素から返されたワークフロー オブジェクトを次の構成要素に渡すことができます。 コンパイラは、計算式を解析するときに、上の表のメソッドと計算式内のコードを使用して、計算式を一連の入れ子になった関数呼び出しに変換します。
入れ子になった式は、次のような形式をしています。
builder.Run(builder.Delay(fun () -> {| cexpr |}))
上記のコードで、Run と Delay の呼び出しが計算式ビルダー クラスで定義されていない場合、それらの呼び出しは省略されます。 計算式の本体 (ここでは {| cexpr |} で表される) は、次の表に示す変換によって、ビルダー クラスのメソッドを含む呼び出しに変換されます。 計算式 {| cexpr |} は、これらの変換に従って再帰的に定義されます。ここで、expr は F# 式で、cexpr は計算式です。
式 |
変換 |
---|---|
{| let binding in cexpr |} |
let binding in {| cexpr |} |
{| let! pattern = expr in cexpr |} |
builder.Bind(expr, (fun pattern -> {| cexpr |})) |
{| do! expr in cexpr |} |
builder.Bind(expr1, (fun () -> {| cexpr |})) |
{| yield expr |} |
builder.Yield(expr) |
{| yield! expr |} |
builder.YieldFrom(expr) |
{| return expr |} |
builder.Return(expr) |
{| return! expr |} |
builder.ReturnFrom(expr) |
{| use pattern = expr in cexpr |} |
builder.Using(expr, (fun pattern -> {| cexpr |})) |
{| use! value = expr in cexpr |} |
builder.Bind(expr, (fun value -> builder.Using(value, (fun value -> {| cexpr |})))) |
{| if expr then cexpr0 |} |
if expr then {| cexpr0 |} else binder.Zero() |
{| if expr then cexpr0 else cexpr1 |} |
if expr then {| cexpr0 |} else {| cexpr1 |} |
{| match expr with | pattern_i -> cexpr_i |} |
match expr with | pattern_i -> {| cexpr_i |} |
{| for pattern in expr do cexpr |} |
builder.For(enumeration, (fun pattern -> {| cexpr }|)) |
{| for identifier = expr1 to expr2 do cexpr |} |
builder.For(enumeration, (fun identifier -> {| cexpr }|)) |
{| while expr do cexpr |} |
builder.While(fun () -> expr), builder.Delay({|cexpr |}) |
{| try cexpr with | pattern_i -> expr_i |} |
builder.TryWith(builder.Delay({| cexpr |}), (fun value -> match value with | pattern_i -> expr_i | exn -> reraise exn))) |
{| try cexpr finally expr |} |
builder.TryFinally(builder.Delay( {| cexpr |}), (fun () -> expr)) |
{| cexpr1; cexpr2 |} |
builder.Combine({|cexpr1 |}, {| cexpr2 |}) |
{| other-expr; cexpr |} |
expr; {| cexpr |} |
{| other-expr |} |
expr; builder.Zero() |
この表で、other-expr は表に示されていない式を表します。 ビルダー クラスでは、すべてのメソッドを実装して、この表に示されているすべての変換をサポートする必要はありません。 実装されていない構成要素は、その型の計算式では使用できません。 たとえば、計算式で use キーワードをサポートしない場合は、ビルダー クラスで Use の定義を省略できます。
次のコード例では、単純な計算式の型を作成および使用して、コード実行の進行状況を追跡するコンソール出力を生成しています。
// Program.fs
open Module1
// Create the computation expression object.
let trace1 = trace {
// A normal let expression (does not call Bind).
let x = 1
// A let expression that uses the Bind method.
let! y = 2
let sum = x + y
// return executes the Return method.
return sum
}
// Execute the code. Start with the Delay method.
let result = trace1()
次のコードは、トレース計算式のビルダー クラスを実装します。
// Module1.fs
module Module1 =
// Functions that implement the builder methods.
let bind value1 function1 =
printfn "Binding %A." value1
function1 value1
let result value1 =
printfn "Returning result: %A" value1
fun () -> value1
let delay function1 =
fun () -> function1()
// The builder class for the "trace" workflow.
type TraceBuilder() =
member x.Bind(value1, function1) =
bind value1 function1
member x.Return(value1) = result value1
member x.Delay(function1) =
printfn "Starting traced execution."
delay function1
let trace = new TraceBuilder()
この例の出力は次のようになります。
Starting traced execution.
Binding 2.
Returning result: 3
参照
その他の技術情報
履歴の変更
日付 |
履歴 |
理由 |
---|---|---|
2010 年 12 月 |
Run メソッドと変換の表を追加。 |
カスタマー フィードバック |
2011 年 4 月 |
ビルダー メソッドの表で Yield を追加し、For のシグネチャを更新。 |
コンテンツ バグ修正 |