递归更新State Monad

时间:2013-12-03 17:21:56

标签: f# monads state-monad

此问题与this question

有关

我有一个州monad。对象提供OOD strategy pattern中的update函数。

  • 拥有一个对象的选择是在真实的生产代码中 class提供了一个操作数组,通过所有共享状态 单子。继承帮助我扩展了基本功能 进一步定制提供操作的类。
  • 在类中选择monad而不是mutable属性是monad通过正确使用泛型,帮助我抽象并更灵活地将变量/信息带到计算中作为“状态” ”

我有一个简单的玩具示例:

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



/////////////////////////////////////////////////////////////////////////////////////
// Definition of the State monad type
/////////////////////////////////////////////////////////////////////////////////////
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')

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

let runState f init = f init        

/////////////////////////////////////////////////////////////////////////////////////
// STRATEGY PATTERN
/////////////////////////////////////////////////////////////////////////////////////

let state = StateMonadBuilder<int> ()

// DoubleFunctOne defines standard operations that remain always the same
type Strategy (aFunction) =
    member this.Update (x: int) = state {
        let! currState = state.getState
        let processedx = aFunction x
        do! state.putState (currState + x) }

// Create a function that customizes the strategy 
let myFunction x = 
    2 * x

// Customize the strategy with the desired function:
let strategy = Strategy (myFunction)    



/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Update recursively
/////////////////////////////////////////////////////////////////////////////////////////////////////////

// ?? How to run update recursively ??
let result initialCondition = 
    initialCondition
    |> (for i = 10 to 100 do 
            yield state { do! strategy.Update i } )

我的目标是应用初始条件,获取数据并递归(在forwhile循环内,甚至在某些功能操作中)strategy提供的功能。与monad合作,我不知道该怎么做。

谢谢。

计算表达式

受@kvb回答的启发,我在计算表达式中添加了for方法。

// Loops through seqnc of numbers that constitute an input to func
member b.For (seqnc:_ List, func) =
    seqnc
    |> List.map (fun item -> func item)
    |> List.reduce (fun acc item -> 
            (fun s ->
                let _, s' = acc s
                item s' ) )

我进行了一些测试,我觉得这个测试有效。 感谢。

1 个答案:

答案 0 :(得分:1)

这样的东西?

let result initialCondition =
    let rec loop = function
    | 101 -> state { return () }
    | i -> 
        state {
            do! strategy.Update i
            do! loop (i+1)
        }
    initialCondition
    |> runState (loop 10)

或者,在构建器上定义For成员,并以更加强制的方式编写它:

let result initialCondition =
    let f = state {
        for i in 10 to 100 do
            do! strategy.Update i
    }
    initialCondition
    |> runState f

另请注意,您对Strategy.Update的定义可能存在错误:processedx已绑定但尚未使用。