【问题标题】:Recursively update a State Monad递归更新状态单子
【发布时间】:2013-12-03 17:21:55
【问题描述】:

这个问题与this question有关

我有一个状态单子。对象提供update 函数,如OOD strategy pattern

  • 拥有对象的选择是在实际的生产代码中, 类提供了一个操作数组,所有通过 单子。继承帮助我扩展了基本功能和 进一步自定义提供操作的类。
  • 在类中使用 monad 而不是可变属性的选择是,通过正确使用泛型,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' ) )

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

【问题讨论】:

    标签: f# monads state-monad


    【解决方案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 已绑定但未使用。

    【讨论】:

    • 不应该是return! loop (i+1),还是在这种情况下没关系?
    • @ildjarn - 因为loopint -&gt; StateFunc&lt;int,unit&gt; 类型,所以没关系。
    猜你喜欢
    • 1970-01-01
    • 2021-06-26
    • 1970-01-01
    • 2020-06-19
    • 1970-01-01
    • 2021-03-30
    • 2021-04-23
    • 1970-01-01
    • 2012-04-27
    相关资源
    最近更新 更多