Random / State workflow in F# -


i'm trying wrap head around mon-, err, workflows in f# , while think have pretty solid understanding of basic "maybe" workflow, trying implement state workflow generate random numbers has got me stumped.

my non-completed attempt can seen here:

let randomint state =     let random = system.random(state)     // generate random number , new state     random.next(0,1000), random.next()   type randomwf (initstate) =     member this.bind(rnd,rest) =         let value, newstate = rnd initstate         // how feed "newstate" "rest"??         value |> rest     member this.return = // should maybe feed "initstate" computation here?  randomwf(0) {     let! = randomint     let! b = randomint     let! c = randomint     return [a; b; c] } |> printfn "%a" 

edit: got work! not sure how works though, if wants lay out in answer, it's still grabs. here's working code:

type randomwf (initstate) =     member this.bind(rnd,rest) =         fun state ->             let value, nextstate = rnd state             rest value nextstate      member this.return = fun _ ->       member this.run x = x initstate 

there 2 things make harder see workflow doing:

  1. you're using function type type of monad,
  2. your workflow not builds computation, runs it.

i think it's clearer follow once see how without 2 impediments. here's workflow defined using du wrapper type:

type random<'a> =      comp of (int -> 'a * int)  let run init (comp f) = f init  type random<'a>      member this.run(state) = fst <| run state   type randombuilder() =     member this.bind(comp m, f: 'a -> random<_>) =         comp <| fun state ->             let value, nextstate = m state             let comp = f value             run nextstate comp                   member this.return(a) = comp (fun s -> a, s)  let random = randombuilder() 

and here how use it:

let randomint =     comp <| fun state ->         let rnd = system.random(state)         rnd.next(0,1000), rnd.next()  let rand =     random {         let! = randomint         let! b = randomint         let! c = randomint         return [a; b; c ]     }  rand.run(0) |> printfn "%a" 

in version separately build computation (and store inside random type), , run passing in initial state. @ how types on builder methods inferred , compare them msdn documentation describes.

edit: constructing builder object once , using binding alias of sorts convention, it's justified in makes sense builders stateless. can see why having parameterized builders seems useful feature, can't imagine convincing use case it.

the key selling point of monads separation of definition , execution of computation.

in case - want able take representation of computation , able run state - perhaps 0, perhaps 42. don't need know initial state define computation use it. passing in state builder, end blurring line between definition , execution, , makes workflow less useful.

compare async workflow - when write async block, don't make code run asynchronously. create async<'a> object representing computation produce object of 'a when run - how it, you. builder doesn't need know.


Comments