2014-01-27 4 views
4

Этот вопрос был вдохновлен this question. Я понимаю пример (ListBuilder), но мне не удалось создать цикл while для моей государственной монады. Мне не ясно, как bind тело цикла while, так как итерации следуют друг за другом.State Monad - While-loops

спасибо.

///////////////////////////////////////////////////////////////////////////////////// 
// Definition of the state 
///////////////////////////////////////////////////////////////////////////////////// 
type StateFunc<'State, 'T> = 'State -> 'T * 'State 



///////////////////////////////////////////////////////////////////////////////////// 
// Definition of the State monad 
///////////////////////////////////////////////////////////////////////////////////// 
type StateMonadBuilder<'State>() = 

    // M<'T> -> M<'T> 
    member b.ReturnFrom a : StateFunc<'State, 'T> = a 

    // 'T -> M<'T> 
    member b.Return a : StateFunc<'State, 'T> = (fun s -> a, s) 

    // M<'T> * ('T -> M<'U>) -> M<'U> 
    member b.Bind(p : StateFunc<_, 'T>, rest : 'T -> StateFunc<_,_>) : StateFunc<'State, 'U> = 
     (fun s -> 
      let a, s' = p s 
      rest a s') 

    member b.Zero() = fun s ->(), s 

    member b.Delay f = f 

    member b.Run f = f() 

    // Getter for the whole state, this type signature is because it passes along the state & returns the state 
    member b.getState : StateFunc<'State, _> = (fun s -> s, s) 

    // Setter for the state 
    member b.putState (s:'State) : StateFunc<'State, _> = (fun _ ->(), s) 

    // (unit -> bool) * M<'T> -> M<'T> 
    member b.While (cond, body: StateFunc<'State, _>): StateFunc<'State, _> = 
     (fun s -> 
      if cond() then 
       let bind = 
        let _, s' = body s 
        fun s' -> body s'  
       b.While (cond, bind) // This is wrong 
      else 
       body s) 
+1

Код вашего примера выглядит из [ExtCore] (https://github.com/jack- Pappas/ExtCore). Вы посмотрели код там, чтобы увидеть, включает ли оно определение для члена 'While' типа' StateBuilder'? –

+0

Awesome. Я нашел его на странице https://github.com/jack-pappas/ExtCore/blob/master/ExtCore/Control.fs. Спасибо. – NoIdeaHowToFixThis

ответ

4

Если вы посмотрите на различные вычисления строителей в ExtCore, есть одна интересная вещь, чтобы отметить - для любой монады, реализация члена While (а также For), как правило, то же самое.

Это потому, что вы всегда можете выразить операцию в терминах Bind, Zero и рекурсивным использованием While. Так что, если вы работаете с монадой, вы всегда будете определить что-то вроде этого (просто заменить M<_> с монадой):

// (unit -> bool) * M<'T> -> M<'T> 
member this.While (guard, body : M<_>) : M<_> = 
    if guard() then 
     this.Bind (body, (fun() -> this.While (guard, body))) 
    else 
     this.Zero() 

Это не верно для всех вычислений - если вычисление более интересное в некотором роде , то может потребоваться другая реализация While, но вышеописанное является разумным значением по умолчанию.

Кроме того, я считаю, что необходимость определения пользовательских вычислений в F # должна быть довольно редкой - идиоматический код F # не использует монады почти так же часто, как, например, Haskell и большую часть времени, вы должны быть в порядке с тем, что имеет стандартная библиотека (или то, что определяет ExtCore, если вы делаете что-то более продвинутое). Возможно, вам нужен пользовательский расчет, но имейте в виду, что это может быть отвлечением, ведущим вас в неправильном направлении ...

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