FSharpx.Extras


#r @"../bin/FSharpx.Extras.dll"
#r @"../bin/FSharpx.Collections.dll"

open System
open System.Threading
open FSharpx

type MyStateRecord =
    {
        X:int
        Y:string
    }
type MyResultType =
    {
        R: double
    }

let ``nested step without result`` : State.State<unit,MyStateRecord> =
    State.state {
        printfn "Starting ``nested step without result``"
        
        let! s = State.getState
        do! State.putState {s with X = s.X+1}
        printfn "Ending ``nested step without result``"
    }

let ``nested step with same state type, but different result type`` : State.State<char,MyStateRecord> =
    State.state {
        printfn "Starting ``nested step with same state type, but different result type``"
        
        printfn "Getting the state sn1 inside nested step "
        let! sn1 = State.getState
        printfn "sn1: %A" sn1

        printfn "Writing state inside nested step"
        do! State.putState {sn1 with X=0;  Y="nested Step"}
        printfn "Getting the state sn2 inside nested step "
        let! sn2 = State.getState
        
        printfn "Notice that put does not mutate sn1"
        printfn "sn1: %A" sn1
        printfn "sn2: %A" sn2
        
        printfn "Ending ``nested step with same state type, but different result type``"
        return (char sn1.X)
    }

let ``computation using state monad``  : State.State<MyResultType, MyStateRecord> =
    State.state {
        printfn "Starting ``computation using state monad``"
        printfn "Getting state value s1"
        let! s1 = State.getState
        printfn "s1: %A" s1

        printfn "Writing state"
        do! State.putState {s1 with Y = "first put"}
        printfn "Getting state value s2"
        let! s2 = State.getState
        printfn "s2: %A" s2

        printfn "Start nested step resulting in c1"
        let! c1 = ``nested step with same state type, but different result type``
        printfn "End nested step resulting in c1"
        printfn "Getting state value s3"
        let! s3 = State.getState
        printfn "c1: %A, s3: %A" c1 s3

        printfn "Start nested step without result (increases X by one)"
        do! ``nested step without result``
        printfn "End nested step resulting"
        printfn "Getting state value s4"
        let! s4 = State.getState
        printfn "s4: %A" s4
        
        printfn "double c1: %A double s4.X: %A" (double c1) (double s4.X)
        printfn "Ending ``computation using state monad``"
        return {R= 123.0 + double c1 + double s4.X}
    }

let run () =
    let startingState = {X = 42; Y="start"}
    
    printfn "You can get both result and state by providing the State monad with start state"
    printfn "(Notice that computation won't start until you provide `startState`)"
    let (result, endState) = ``computation using state monad`` startingState
    printfn "result: %A, endState: %A" result endState
    printfn ""
    printfn ""
    printfn ""
    printfn "Or result only with `eval`"
    printfn "(Notice recomputation)"
    let resultOnly = State.eval ``computation using state monad`` startingState
    printfn "resultOnly: %A" resultOnly
    printfn ""
    printfn ""
    printfn ""
    printfn "Or endState only with `exec`"
    let onlyEndState = State.exec ``computation using state monad`` startingState
    printfn "onlyEndState: %A" onlyEndState
    ()
namespace System
namespace System.Threading
namespace FSharpx
type MyStateRecord = { X: int Y: string }
MyStateRecord.X: int
Multiple items
val int: value: 'T -> int (requires member op_Explicit)

--------------------
type int = int32

--------------------
type int<'Measure> = int
MyStateRecord.Y: string
Multiple items
val string: value: 'T -> string

--------------------
type string = String
type MyResultType = { R: double }
MyResultType.R: double
Multiple items
val double: value: 'T -> double (requires member op_Explicit)

--------------------
type double = Double

--------------------
type double<'Measure> = float<'Measure>
type unit = Unit
val printfn: format: Printf.TextWriterFormat<'T> -> 'T
Multiple items
val char: value: 'T -> char (requires member op_Explicit)

--------------------
type char = Char
val run: unit -> unit
val startingState: MyStateRecord
val result: obj
val endState: obj
val resultOnly: obj
val onlyEndState: obj