<Query Kind="FSharpProgram" />

open System.Threading
open System.Threading.Tasks

// unit : 'T -> Task<'T>
let inline unit t = Task.FromResult t
let inline unit1 (m:Task<'T>) = m.Result

// bind : ('T -> Task<'U>) -> (Task<'T> -> Task<'U>)
let inline bind g (m:Task<'T>) = 
    let t = m.Result  // blocking call :(
    g t

type MyTaskBuilder () =
  member this.Bind (m, g) = 
    bind g m
  member this.Return t = 
    unit t
  member this.ReturnFrom m = 
    m

let mytask = MyTaskBuilder ()

// a, b, c : int -> Task<int>
let a x = mytask { return x+1 }
let b y = mytask { return y+y }
let c z = mytask { return z*z}

// d : int -> Task<int>
let d x = mytask {  
    let! y = a x   
    let! z = b y    
    return! c z    
    }

let d' x = 
    mytask.Bind (a x, 
        fun y -> 
            mytask.Bind (b y,
                fun z -> mytask.ReturnFrom c z))

let d'' x = 
    bind 
        (fun y -> bind c (b y)) 
        (a x)

let d''' x = 
    //x |> (a >> bind b >> bind c)
    a x |> (bind b >> bind c)

let w = unit1 (d 3)
let w' = unit1 (d' 3)
let w'' = unit1 (d'' 3)
let w''' = unit1 (d''' 3)

printfn "w:%d, w':%d, w'':%d, w''':%d" w w' w'' w'''

// ---
printfn ""

// (>>=) : Task<'T> -> ('T -> Task<'U>) -> Task<'U>
let inline (>>=) m f = m |> (bind f) // bind f m

// (>=>) : ('T -> Task<'U>) -> ('U -> Task<'V>) -> ('T -> Task<'V>)
let inline (>=>) f g = f >> (bind g)

let k x = x |> (a >=> b >=> c)

let h = unit1 (k 3)
printfn "h:%d" h

//