8

Whileビルダーオブジェクトのメソッドを定義する場合は、計算式whileで-loopsを使用できます。メソッドのシグネチャは次のとおりです。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で複数回実行することは不可能です。

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

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

4

1 に答える 1

4

計算式がどのように評価されるかを見ると、次のことがわかります。

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

次のようなものに翻訳されます

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

この変換により、whileループの本体を複数回評価できます。一部の計算式(seqまたはなど)では型アノテーションは正確ですが、への呼び出しを挿入すると、異なるシグネチャが生成される可能性があることasyncに注意してください。Delayたとえば、次のようなリストビルダーを定義できます。

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()

これで、次のような式を評価できます。

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

に相当するものを取得し[0 .. 9]ます。

ここで、私たちのメソッドには、ではなくWhile署名があります。一般に、操作のタイプが。の場合、メソッドのシグネチャは。になります。(unit -> bool) * (unit -> 'a list) -> 'a list(unit -> bool) * 'a list -> 'a listDelay(unit -> M<'a>) -> D<M<'a>>While(unit -> bool) * D<M<'a>> -> M<'a>

于 2011-01-02T04:26:39.363 に答える