Last active
August 21, 2017 22:34
-
-
Save panesofglass/f36ef58b62dfe65d3380183b276b13bc to your computer and use it in GitHub Desktop.
F# async applicative using a custom operation
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
open System | |
type FSharp.Control.AsyncBuilder with | |
[<CustomOperation("and!", IsLikeZip=true)>] | |
member __.Merge(x, y, f) = | |
async { | |
let! token = Async.CancellationToken | |
let! x' = Async.StartChildAsTask x | |
let! y' = Async.StartChildAsTask y | |
do System.Threading.Tasks.Task.WaitAll([|x';y'|], cancellationToken = token) | |
let! x'' = Async.AwaitTask x' | |
let! y'' = Async.AwaitTask y' | |
return f x'' y'' | |
} | |
member __.For(m, f) = __.Bind(m, f) | |
let a (sw:Diagnostics.Stopwatch) = async { | |
printfn "starting a %O" sw.ElapsedMilliseconds | |
do! Async.Sleep 1000 | |
printfn "returning a %O" sw.ElapsedMilliseconds | |
return 1 | |
} | |
let b (sw:Diagnostics.Stopwatch) = async { | |
printfn "starting b %O" sw.ElapsedMilliseconds | |
do! Async.Sleep 500 | |
do printfn "returning b %O" sw.ElapsedMilliseconds | |
return 2 | |
} | |
let comp sw = async { | |
for x in a sw do | |
``and!`` y in b sw | |
return x + y | |
} | |
let compBind sw = async { | |
let! x = a sw | |
let! y = b sw | |
return x + y | |
} | |
let sw = Diagnostics.Stopwatch.StartNew() | |
let result = comp sw |> Async.RunSynchronously | |
sw.Stop() | |
printfn "comp ran in %Oms with result %i" sw.ElapsedMilliseconds result | |
// Compare with | |
sw.Reset() | |
sw.Start() | |
let resultBind = compBind sw |> Async.RunSynchronously | |
sw.Stop() | |
printfn "compBind ran in %Oms with result %i" sw.ElapsedMilliseconds resultBind | |
let c (sw:Diagnostics.Stopwatch) = async { | |
printfn "starting c %O" sw.ElapsedMilliseconds | |
do! Async.Sleep 1500 | |
do printfn "returning c %O" sw.ElapsedMilliseconds | |
return 3 | |
} | |
let comp3 sw = async { | |
for x in a sw do | |
``and!`` y in b sw | |
``and!`` z in c sw | |
return x + y + z | |
} | |
sw.Reset() | |
sw.Start() | |
let result3 = comp3 sw |> Async.RunSynchronously | |
sw.Stop() | |
printfn "comp3 ran in %Oms with result %i" sw.ElapsedMilliseconds result3 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@gusty, the general idea is, I think, something like what is available in FSharpx.Async. See this thread. There's no reason it must be parallel, but there's no reason it shouldn't be parallel either. It's beneficial that it is parallel for performance reasons.