What is the role of `while`-loops in computation expressions in F#?

半城伤御伤魂 提交于 2019-11-29 19:55:01

问题


If you define a While method of the builder-object, you can use while-loops in your computation expressions. The signature of the While method is:

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

For comparison, the signature of the For method is:

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

You should notice that, in the While-method, the body is a simple type, and not a function as in the For method.

You can embed some other statements, like let and function-calls inside your computation-expressions, but those can impossibly execute in a while-loop more than once.

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

Why is the while-loop not executed more than once, but merely repeated? Why the significant difference from for-loops? Better yet, is there some intended strategy for using while-loops in computation-expressions?


回答1:


If you look at how computation expressions are evaluated, you'll see that

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

is translated to something like

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

This translation allows the body of the while loop to be evaluated multiple times. While your type signatures are accurate for some computation expressions (such as seq or async), note that the insertion of the call to Delay may result in a different signature. For instance, you could define a list builder like this:

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

Now you can evaluate an expression like:

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

to get the equivalent of [0 .. 9].

Here, our While method has the signature (unit -> bool) * (unit -> 'a list) -> 'a list, rather than (unit -> bool) * 'a list -> 'a list. In general, when the Delay operation has type (unit -> M<'a>) -> D<M<'a>>, the While method's signature will be (unit -> bool) * D<M<'a>> -> M<'a>.



来源:https://stackoverflow.com/questions/4577050/what-is-the-role-of-while-loops-in-computation-expressions-in-f

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!