0

这个问题与这个问题有关

我有一个状态单子。对象提供了OOD 策略模式update中的功能。

  • 拥有一个对象的选择是,在实际的生产代码中,该类提供一组操作,所有操作都通过 monad 共享状态。继承帮助我扩展了基本功能并进一步定制了提供操作的类。
  • 在类中使用 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 } )

我的目标是应用初始条件、获取数据并递归地启动(在一个循环或for一个while循环甚至一些函数操作中)由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' ) )

我进行了一些测试,我的印象是这个有效。谢谢。

4

1 回答 1

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但未使用。

于 2013-12-03T18:29:13.113 回答