Государственная монада — циклы while

Этот вопрос был вдохновлен этим вопросом . Я понимаю пример (ListBuilder), но мне не удалось создать цикл while для моей монады состояния. Что мне непонятно, так это как bind тело цикла whileloop, когда итерации следуют одна за другой.

Спасибо.

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

person NoIdeaHowToFixThis    schedule 27.01.2014    source источник
comment
Код вашего примера взят из ExtCore. Вы смотрели на этот код, чтобы увидеть, включает ли он определение члена While типа StateBuilder?   -  person Jack P.    schedule 27.01.2014
comment
Потрясающий. Я нашел один на github.com/jack-pappas/ExtCore/ blob/master/ExtCore/Control.fs. Спасибо.   -  person NoIdeaHowToFixThis    schedule 27.01.2014


Ответы (1)


Если вы посмотрите на различные построители вычислений в 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, если вы делаете что-то более продвинутое). Возможно, вам нужно специальное вычисление, но имейте в виду, что это может отвлекать вас в неправильном направлении...

person Tomas Petricek    schedule 27.01.2014