Skip to content

Instantly share code, notes, and snippets.

@Porges
Last active August 29, 2015 14:09
Show Gist options
  • Save Porges/07b0f56af3f288423298 to your computer and use it in GitHub Desktop.
Save Porges/07b0f56af3f288423298 to your computer and use it in GitHub Desktop.
module F
module State =
type State<'s, 'r> =
// A stateful computation takes an initial state of type 's
// and returns a result of some type 'r and a new state of type 's.
private State of ('s -> 'r * 's)
// You can run a stateful computation by supplying the state value:
let runState (State f : State<'s, 'r>) : 's -> 'r * 's
= f
// Or you can run it and ignore the final state:
let runState_ (s : State<'s, 'r>) : 's -> 'r
= fst << runState s
// A computation expression for stateful computations:
type StateBuilder() =
// Return returns the value without modifying the state:
member this.Return(x : 'r) : State<'s, 'r>
= State (fun s -> (x, s))
member this.Bind(x : State<'s, 'r1>, f : 'r1 -> State<'s, 'r2>) : State<'s, 'r2>
= State (fun (s1 : 's) ->
// Bind performs the first computation using the passed-in state:
let (r, s2) = runState x s1
// Then performs the second using the result and the state from the first:
runState (f r) s2)
// Not sure why F# makes you write this one...
member inline this.ReturnFrom(st : State<'s, 'r>) : State<'s, 'r>
= st
// alias it:
let stateful = StateBuilder()
// You can replace the state:
let putState (x : 's) : State<'s, unit> =
// We ignore the passed-in state and put the state we want into the state slot:
State (fun _ -> ((), x))
// Or you can get the current state:
let getState : State<'s, 's> =
// We simply put the state into both the return value and the state slot:
State (fun s -> (s, s))
module Random =
open State
// Random is just a wrapper around state with an int
// (this is the seed for random number generation).
type Random<'r> =
// We hide the implementation so people can't mess with the state.
private Random of State<int, 'r>
type RandomBuilder() =
// Wrap the stateful computations:
member this.Return(x : 'r) : Random<'r> = Random (stateful { return x })
member this.Bind(Random x : Random<'a>, f : 'a -> Random<'b>) : Random<'b> = Random (stateful {
let! x' = x
let (Random r) = f x'
return! r })
// Running it is just running the state with the specified seed.
let runRandom (Random r : Random<'r>) : int -> 'r = runState_ r
let random = RandomBuilder()
// We also provide a way to generate random numbers (and hence update the seed).
let getRandom : Random<int> = Random (stateful {
let! seed = getState
let r = System.Random(seed)
let result = r.Next()
do! putState (r.Next()) // update the seed
return result
})
// Can provide more than one way...
let getRandomLessThan (max : int) : Random<int> = Random (stateful {
let! seed = getState
let r = System.Random(seed)
let result = r.Next(max)
do! putState (r.Next()) // update the seed
return result
})
open State
// Increments the state until it reaches a target value
// then returns it as a string:
let rec doIt target : State<int, string> = stateful {
let! x = getState
if (x < target)
then
do! putState (x + 1)
return! doIt target
else
return x.ToString()
}
let ten : string = runState_ (doIt 10) 0
open Random
// Provides a random boolean:
let fiftyFifty : Random<bool> = random {
let! r = getRandomLessThan 2
return r = 1
}
// guaranteed random coin flip
let aRandomBoolean : bool = runRandom fiftyFifty 7
module F
module State =
type State<'s, 'r> =
// A stateful computation takes an initial state of type 's
// and returns a result of some type 'r and a new state of type 's.
private State of ('s -> 'r * 's)
// You can run a stateful computation by supplying the state value:
let runState (State f) = f
// Or you can run it and ignore the final state:
let runState_ s = fst << runState s
// A computation expression for stateful computations:
type StateBuilder() =
// Return returns the value without modifying the state:
member this.Return(x) = State (fun s -> (x, s))
member this.Bind(x, f) = State (fun (s1) ->
// Bind performs the first computation using the passed-in state:
let (r, s2) = runState x s1
// Then performs the second using the result and the state from the first:
runState (f r) s2)
// Not sure why F# makes you write this one...
member inline this.ReturnFrom(st) = st
// alias it:
let stateful = StateBuilder()
// You can replace the state:
let putState x = State (fun _ -> ((), x))
// Or you can get the current state:
let getState = State (fun s -> (s, s))
module Random =
open State
// Random is just a wrapper around state with an int
// (this is the seed for random number generation).
type Random<'r> =
// We hide the implementation so people can't mess with the state.
private Random of State<int, 'r>
type RandomBuilder() =
// Wrap the stateful computations:
member this.Return(x) = Random (stateful { return x })
member this.Bind(Random x, f) = Random (stateful {
let! x' = x
let (Random r) = f x'
return! r })
// Running it is just running the state with the specified seed.
let runRandom (Random r) = runState_ r
let random = RandomBuilder()
// We also provide a way to generate random numbers (and hence update the seed).
let getRandom = Random (stateful {
let! seed = getState
let r = System.Random(seed)
let result = r.Next()
do! putState (r.Next()) // update the seed
return result
})
// Can provide more than one way...
let getRandomLessThan max = Random (stateful {
let! seed = getState
let r = System.Random(seed)
let result = r.Next(max)
do! putState (r.Next()) // update the seed
return result
})
open State
// Increments the state until it reaches a target value
// then returns it as a string:
let rec doIt target = stateful {
let! x = getState
if (x < target)
then
do! putState (x + 1)
return! doIt target
else
return x.ToString()
}
let ten = runState_ (doIt 10) 0
open Random
// Provides a random boolean:
let fiftyFifty = random {
let! r = getRandomLessThan 2
return r = 1
}
// guaranteed random coin flip
let aRandomBoolean = runRandom fiftyFifty 7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment