2011-01-02 1 views
7

Если вы определяете метод строителя-объекта While, вы можете использовать while -loops в своем computation expressions. Сигнатура метода While является:Какова роль `while`-циклов в выражениях вычислений в F #?

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 -loop более одного раза.

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

Почему while не -loop выполняется более чем один раз, а лишь повторил? Почему существенное отличие от for-loops? Еще лучше, есть ли какая-то предполагаемая стратегия использования while-loops в выражениях вычислений?

ответ

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

Этот перевод позволяет тело цикла в то время, чтобы оценить несколько раз. Хотя ваши сигнатуры типа являются точными для некоторых выражений вычисления (например, 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>.

+0

Nice. Я не знал о «Run». –

 Смежные вопросы

  • Нет связанных вопросов^_^