I have a series of operations. The operations have been modeled as state monads.
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')
member b.Zero() =
(fun s -> (), 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
The operations have been designed to run in parallel. In most of the applications the operations are executed independently. There might be a user case where the operations must receive status updates from one environmental entity. In theory, the environmental entity carries its own state and it could be modeled as a state monad itself.
I was wondering how this could be solved in functional style. I have read something about monad trasnformers, but I am not sure this it is the way to go.
(I am trying to work on an example, but I am not sure about a proper toy problem)
EDIT 3
Based on the comments and the suggestions below, I have tried to build an agent. My goal is to mount the State Monad on the agent. That will allow me to reuse the code already built. I'd also would like to understand and solve this problem, in order to gain insights about how F# works.
I have prepared the following toy example:
/////////////////////////////////////////////////////////////////////////////////////
// Definition of the state
/////////////////////////////////////////////////////////////////////////////////////
type StateFunc<'State, 'T> = 'State -> 'T * 'State
/////////////////////////////////////////////////////////////////////////////////////
// Definition of the State monad
/////////////////////////////////////////////////////////////////////////////////////
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')
member b.Zero() = fun s -> (), s
member b.Delay (f : unit -> StateFunc<_,_>) : StateFunc<'State, 'T> =
b.Bind (b.Return (), f)
// 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)
// (unit -> bool) * M<'T> -> M<'T>
member this.While (guard, body : StateFunc<_,_>) : StateFunc<'State, unit> =
if guard () then
this.Bind (body, (fun () -> this.While (guard, body)))
else
this.Zero ()
/////////////////////////////////////////////////////////////////////////////////////
// The agent
/////////////////////////////////////////////////////////////////////////////////////
let state = StateMonadBuilder<int> ()
type SonM (sonName: string) =
let name = sonName
member this.GetMoneyFromDad (x: int) = state {
printfn " I am getting money from dad"
let! currState = state.getState
do! state.putState (currState + x)
do! this.ToConsole () }
member this.GoShopping (x: int) = state {
printfn " I am taken to the mall"
let! currState = state.getState
do! state.putState (currState - x)
do! this.ToConsole () }
member this.TellDad = state {
printfn " I'll tell dad my balance "
return! state.getState }
member this.ToConsole () = state {
let! mystate = state.getState
printfn " Balance: %i" mystate }
type Agent<'T> = MailboxProcessor<'T>
type message =
| Shopping of int
| Allowance of int
| GetBalance
| Stop
let setupAgent iv = Agent.Start (fun inbox ->
let aSon = new SonM ("Paul")
let processMsg msg = state {
match msg with
| Shopping money ->
printfn "Go shopping with %i " money
do! (aSon.GoShopping money)
| Allowance money ->
printfn " I got some money for you, son"
do! (aSon.GetMoneyFromDad money)
| GetBalance ->
printfn " Calling: TellDad"
let! balance = aSon.TellDad
printfn " Current Balance: %i" balance
printfn " The balance should have been printed"
| _ -> do printfn "Nothing to do.." }
let rec loop () =
let getMsgAsync () = async {
let! msg = inbox.Receive()
return processMsg msg }
let p =
(fun s ->
let _, s' = (getMsgAsync () |> Async.Start) s
getMsgAsync s')
state.Bind ( /// ??? WIP HERE ??? )
iv |> loop () )
let agent = setupAgent 100
agent.Post (GetBalance)
agent.Post(Allowance 15)
agent.Post (GetBalance)
agent.Post (Shopping 10)
agent.Post (Stop)
I am unsure on how to proceed to 'bind' states within the async
recursive loop that defines the agent. Thanks.