this question is related to this question
I have a state monad. An object provides an update
function as in the OOD strategy pattern.
- The choice of having a object is that in real, production code, the class provides an array of operations, all sharing state through the monad. Inheritance helped me extend the basic functionality and further customizing the class providing the operations.
- The choice of having a monad instead of a mutable property within the class is that the monad, through proper use of generics, is helping me abstracting and being more flexible on what variables/information must be carried along the computation as "state".
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?
Alternatively, define a
For
member on your builder and write it the more imperative way:Also, note that there is likely a bug in your definition of
Strategy.Update
:processedx
is bound but unused.