Last active
August 29, 2015 14:09
-
-
Save Porges/07b0f56af3f288423298 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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