Hope the following may help

 

#light

namespace Common.Monads

type State<'state,'a> = State of ('state -> 'a * 'state)

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]    
module State = begin
  type StateBuilder =
    class
      new : unit -> StateBuilder
      member Bind : m:State<'state,'a> * f:('a -> State<'state,'b>) -> State<'state,'b>
      member BindUsing : m:State<'state,'a> * f:('a -> State<'state,'b>) ->State<'state,'b> when 'a :> System.IDisposable
      member Combine : m1:State<'state,unit> * m2:State<'state,'a> -> State<'state,'a>
      member Delay : f:(unit -> State<'state,'a>) -> State<'state,'a>
      member For : s:#seq<'a> * f:('a -> State<unit,'b>) -> State<unit,unit>
      //member Let : x:'a * f:('a -> 'b) -> 'b
      member Return : x:'a -> State<'state,'a>
      member TryFinally : m:State<'state,'a1> * f:(unit -> unit) -> State<'state,'a1>
      member TryWith : m:State<'state,'a> * f:(exn -> State<'state,'a>) -> State<'state,'a>
      member Using : x:'a * f:('a -> State<'state,'b>) -> State<'state,'b> when 'a :> System.IDisposable
      member While : p:(unit -> bool) * m:State<unit,'a> -> State<unit,unit>
      member Zero : unit -> State<'state,unit>
    end

  ///[state {...}] is the [State] continuation builder. 
  val state : StateBuilder
  
  ///[Run m state] runs [m] with the [state] and returns the value and state. 
  val Run : State<'state,'a> -> 'state -> 'a * 'state
  
  ///[GetState] is a continuation returning the current state of the continuation.
  ///Example of use : [state { let! state = get ... }]
  val GetState : State<'state,'state>
  
  ///[SetState newState] is a continuation putting [newState] as the new state of the continuation.
  ///Example of use : [state { do! put newState }]  
  val SetState : 'state -> State<'state,unit>

  ///[MapState f] is a continuation putting [f oldState] as the new state of the continuation.
  ///Example of use : [state { do! modify (fun oldState -> oldState) }]    
  val MapState : ('state -> 'state) -> State<'state,unit>

  ///[Eval m s] returns the state of [m] at the end of the continuation computation 
  ///which has used [s] as its initial state.    
  val Eval : State<'state,'a> -> 'state -> 'state
  
  ///[Exec m s] returns the value of [m] at the end of the continuation computation 
  ///which has used [s] as its initial state.
  val Exec : State<'state,'a> -> 'state -> 'a
  
  ///[MapStateAndResult f m] returns a new [State] continuation by applying [f value state] where
  ///[value] and [state] are the value and state of [m].
  val MapStateAndResult : ('a -> 'state -> 'b * 'state) -> State<'state,'a> -> State<'state,'b>
end

 


//=======================================

#light

namespace Common.Monads

open System

type State<'state, 'a> = State of ('state ->'a * 'state)

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]      
module State =
  let private succeed x = State (fun s -> x, s)
  let Run (State f) s = f s

  let private bind m f =
    State (fun s ->
      let v, s = Run m s 
      Run (f v) s
    )    
    
  let private delay f = State (fun s -> Run (f()) s)
  
  let private try_with m f = State (fun s -> try Run m s with e -> Run (f e) s)

  let private try_finally m f = State (fun s -> try Run m s finally f())
  let private dispose (x: #IDisposable) = x.Dispose()
  let private using r f = try_finally  (f r) (fun () -> dispose r)

  let rec private do_while p m = 
    if p() then 
      bind m (fun _ -> do_while p m) 
    else 
      succeed ()

  type StateBuilder () = 
    member b.Bind(m, f) = bind m f
    member b.BindUsing(m, f) = bind m (fun r -> using r f)
    member b.Combine(m1, m2) = bind m1 (fun () -> m2)  
    member b.Delay(f) = delay f

    member b.For(s:#seq<_>, f:('a->State<unit, 'b>)) = 
      using (s.GetEnumerator()) (fun ie ->
        do_while (fun () -> ie.MoveNext()) (delay (fun() -> f ie.Current))
      )

//    member b.Let(x, f) = f x

    member b.Return(x) = succeed x
    member b.TryFinally (m, f) = try_finally m f
    member b.TryWith(m, f) = try_with m f
    member b.Using(x : #IDisposable, f) = try_finally (f x) (fun () -> x.Dispose())
    member b.While(p, m:State<unit, 'a>) = do_while p m
    member b.Zero() = succeed ()

  let state = StateBuilder()
  let GetState = State (fun s -> s, s)
  let SetState s = State (fun _ -> (), s)

  let MapState f =
    State (fun s ->(), f s)

  let Eval m s =
    let _, s = Run m s
    s

  let Exec m s =
    let v, _ = Run m s
    v

  let MapStateAndResult f m =
    State (fun s ->
      let v, s = Run m s 
      let v', s' = f v s 
      Run (succeed v') s'
    )    

//Example

#r "FSharp.PowerPack.dll"

open State

//State<int, int>
let test = 
  state 
    { let! x = GetState
      let y = 100
      do! SetState (x + y * 100)
      return x
   }

let _ =
  let seed = 100
  System.Console.WriteLine("seed:{0}", seed)
  System.Console.WriteLine("test : Run:{0}", Run test seed)
  System.Console.WriteLine("test : value:{0} \t state:{1}", Exec test seed, Eval test seed)


//State<foo, int>
//with type foo = {a : int ; mutable b  :int }

type foo = {a : int ; mutable b  :int }

let test =
  state 
   { let! x = GetState
     print_endline ("pre " + any_to_string x)
     do! MapState (fun x -> {x with a = 700})
     let! x = GetState
     print_endline ("post " + any_to_string x)
     let! x = GetState
     return ()
   }

let _ = Run test {a = 0; b = 0}
    

By on 10/17/2008 10:13 AM ()
Thanks a lot, much appreciated!

I guess I was thinking of having the get/put as members on the builder, but of course the little GetState and MapState combinators do the trick nicely.
By on 10/17/2008 10:37 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us
Built with WebSharper