2011-01-02 13 views
7

ビルダーオブジェクトのWhileメソッドを定義する場合は、computation expressionswhile -loopsを使用できます。 Whileメソッドのシグネチャは次のとおりです。比較のためにF#の計算式のwhileループの役割は何ですか?

member b.While (predicate:unit->bool, body:M<'a>) : M<'a> 

Forメソッドのシグネチャは次のとおりです。

member b.For (items:seq<'a>, body:unit->M<'a>) : M<'a> 

あなたはWhile -methodで、体が単純型である、ということに気づくはずです、Forメソッドのような関数ではありません。

letなどの他の文を計算式内に埋め込むことはできますが、それらはwhile -loopで複数回実行することは不可能です。

builder { 
    while foo() do 
     printfn "step" 
     yield bar() 
} 

はなぜwhile -loopが複数回実行されていませんが、単に繰り返さ?なぜfor-loopsとの大きな違いですか?さらに、計算式でwhileループを使用するための戦略がいくつかありますか?

答えて

3

あなたはhow computation expressions are evaluatedを見れば、あなたは

while foo() do 
    printfn "step" 
    yield bar() 

は、この翻訳はwhileループの本体が複数回評価されることを可能にする

builder.While(fun() -> foo(), 
       builder.Delay(fun() -> 
           printfn "step" 
           builder.Yield(bar())))) 

のようなものに変換されていることがわかります。いくつかの計算式(たとえばseqまたはasync)の型シグネチャは正確ですが、Delayへの呼び出しを挿入すると、異なる署名が返されることに注意してください。たとえば、あなたは次のようにリストビルダーを定義することができます:[0 .. 9]と同等のものを得るために

list { 
    let x = ref 0 
    while !x < 10 do 
    yield !x 
    x := !x + 1 
} 

type ListBuilder() = 
    member x.Delay f = f 
    member x.While(f, l) = if f() then l() @ (x.While(f, l)) else [] 
    member x.Yield(i) = [i] 
    member x.Combine(l1,l2) = l1 @ l2() 
    member x.Zero() = [] 
    member x.Run f = f() 

let list = ListBuilder() 

は今、あなたのような式を評価することができます。

ここで、Whileメソッドは、(unit -> bool) * 'a list -> 'a listではなく、(unit -> bool) * (unit -> 'a list) -> 'a listというシグニチャを持っています。一般に、Delayの操作が(unit -> M<'a>) -> D<M<'a>>の型の場合、Whileメソッドの署名は(unit -> bool) * D<M<'a>> -> M<'a>になります。

+0

ニース。私は 'Run'について知らなかった。 –

関連する問題