Created
March 19, 2021 04:51
-
-
Save matthewcrews/701465b42a6f9da86144cc1a74d64357 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
/// State is a function type that takes a state and | |
/// returns a value and the new state. | |
/// Single case union of the same type. | |
type State<'a, 's> = ('s -> 'a * 's) | |
module State = | |
// Explicit | |
// let result x : State<'a, 's> = fun s -> x, s | |
// Less explicit but works better with other, existing functions: | |
let result x s = | |
x, s | |
let bind (f:'a -> State<'b, 's>) (m:State<'a, 's>) : State<'b, 's> = | |
// return a function that takes the state | |
fun s -> | |
// Get the value and next state from the m parameter | |
let a, s' = m s | |
// Get the next state computation by passing a to the f parameter | |
let m' = f a | |
// Apply the next state to the next computation | |
m' s' | |
/// Evaluates the computation, returning the result value. | |
let eval (m:State<'a, 's>) (s:'s) = | |
m s | |
|> fst | |
/// Executes the computation, returning the final state. | |
let exec (m:State<'a, 's>) (s:'s) = | |
m s | |
|> snd | |
/// Returns the state as the value. | |
let getState (s:'s) = | |
s, s | |
/// Ignores the state passed in favor of the provided state value. | |
let setState (s:'s) = | |
fun _ -> | |
(), s | |
type StateBuilder() = | |
member __.Return(value) : State<'a, 's> = | |
State.result value | |
member __.Bind(m:State<'a, 's>, f:'a -> State<'b, 's>) : State<'b, 's> = | |
State.bind f m | |
member __.ReturnFrom(m:State<'a, 's>) = | |
m | |
member __.Zero() = | |
State.result () | |
member __.Delay(f) = | |
State.bind f (State.result ()) | |
let rng = System.Random(123) | |
type StepId = StepId of int | |
type Food = | |
| Chicken | |
| Rice | |
type Step = | |
| GetFood of StepId * Food | |
| Eat of StepId * Food | |
| Sleep of StepId * duration:int | |
type PlanAcc = PlanAcc of lastStepId:StepId * steps:Step list | |
let state = StateBuilder() | |
let getFood = | |
state { | |
printfn "GetFood" | |
let randomFood = | |
if rng.NextDouble() > 0.5 then Food.Chicken | |
else Food.Rice | |
let! (PlanAcc (StepId lastStepId, steps)) = State.getState | |
let nextStepId = StepId (lastStepId + 1) | |
let newStep = GetFood (nextStepId, randomFood) | |
let newAcc = PlanAcc (nextStepId, newStep::steps) | |
do! State.setState newAcc | |
return randomFood | |
} | |
let sleepProgram duration = | |
state { | |
printfn "Sleep: %A" duration | |
let! (PlanAcc (StepId lastStepId, steps)) = State.getState | |
let nextStepId = StepId (lastStepId + 1) | |
let newStep = Sleep (nextStepId, duration) | |
let newAcc = PlanAcc (nextStepId, newStep::steps) | |
do! State.setState newAcc | |
} | |
let eatProgram food = | |
state { | |
printfn "Eat: %A" food | |
let! (PlanAcc (StepId lastStepId, steps)) = State.getState | |
let nextStepId = StepId (lastStepId + 1) | |
let newStep = Eat (nextStepId, food) | |
let newAcc = PlanAcc (nextStepId, newStep::steps) | |
do! State.setState newAcc | |
} | |
type StateBuilder with | |
[<CustomOperation("sleep", MaintainsVariableSpaceUsingBind=true)>] | |
member this.Sleep (state:State<_,PlanAcc>, duration) = | |
printfn $"Sleep" | |
State.bind (fun _ -> sleepProgram duration) state | |
[<CustomOperation("eat", MaintainsVariableSpaceUsingBind=true)>] | |
member this.Eat (state:State<_,PlanAcc>, food) = | |
printfn $"Eat" | |
State.bind (fun _ -> eatProgram food) state | |
let simplePlan = | |
state { | |
let! food = getFood | |
sleep 2 | |
eat food // <-- This is the error line | |
// It is saying: The value or constructor 'food' is not defined. | |
} | |
let initalAcc = PlanAcc(StepId 0, []) | |
let x = State.exec simplePlan initalAcc | |
x |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The error is on line 120 and says:
