this question is related to this question
I have a state monad. An object provides an update
function as in the OOD strategy pattern.
I have a simple toy example:
/////////////////////////////////////////////////////////////////////////////////////
// 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 } )
My goal is to apply the initial conditions, fetch data and launch recursively (within a for
or a while
loop or even some functional operation) the functions provided by strategy
. Working with the monad, I am not sure how to do this.
Thank you.
Computational Expression For
Inspired by @kvb answer, I have added a for
method to the computational expression.
// 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' ) )
I run a few tests and I have the impression that this one works. Thanks.
Something like this?
let result initialCondition =
let rec loop = function
| 101 -> state { return () }
| i ->
state {
do! strategy.Update i
do! loop (i+1)
}
initialCondition
|> runState (loop 10)
Alternatively, define a For
member on your builder and write it the more imperative way:
let result initialCondition =
let f = state {
for i in 10 to 100 do
do! strategy.Update i
}
initialCondition
|> runState f
Also, note that there is likely a bug in your definition of Strategy.Update
: processedx
is bound but unused.