如果您定义了构建器对象的While
方法,则可以在computation expressions中使用while
- 循环。 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
- 方法中,正文是一种简单类型,而不是For
方法中的函数。
你可以在计算表达式中嵌入一些其他语句,比如let
和函数调用,但是这些语句不可能在while
- 循环中多次执行。
builder {
while foo() do
printfn "step"
yield bar()
}
为什么while
- 循环不会执行多次,而只是重复?为什么与for循环有显着差异?更好的是,是否有一些在计算表达式中使用while循环的策略?
答案 0 :(得分:3)
如果查看how computation expressions are evaluated,您会看到
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 list
。通常,当Delay
操作的类型为(unit -> M<'a>) -> D<M<'a>>
时,While
方法的签名将为(unit -> bool) * D<M<'a>> -> M<'a>
。