From 88fd94ca4f001e956a936c104dbc75e2383deccd Mon Sep 17 00:00:00 2001 From: gusty <1261319+gusty@users.noreply.github.com> Date: Sat, 13 Jan 2024 07:35:34 +0100 Subject: [PATCH] + pmap2 and pmap3 to Async, Task and ValueTask --- src/FSharpPlus/Extensions/Async.fs | 41 ++++++++++++++++++++++++-- src/FSharpPlus/Extensions/Task.fs | 22 ++++++++++++++ src/FSharpPlus/Extensions/ValueTask.fs | 29 ++++++++++++++++++ 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/FSharpPlus/Extensions/Async.fs b/src/FSharpPlus/Extensions/Async.fs index 09fc152ed..71f918b45 100644 --- a/src/FSharpPlus/Extensions/Async.fs +++ b/src/FSharpPlus/Extensions/Async.fs @@ -10,7 +10,7 @@ module Async = let map f x = async.Bind (x, async.Return << f) /// Creates an async workflow from two workflows 'x' and 'y', mapping its results with 'f'. - /// Workflows are run in sequence. + /// Workflows are run in sequence, for parallel use pmap2. /// The mapping function. /// First async workflow. /// Second async workflow. @@ -20,7 +20,7 @@ module Async = return f a b} /// Creates an async workflow from three workflows 'x', 'y' and 'z', mapping its results with 'f'. - /// Workflows are run in sequence. + /// Workflows are run in sequence, for parallel use pmap3. /// The mapping function. /// First async workflow. /// Second async workflow. @@ -31,6 +31,43 @@ module Async = let! c = z return f a b c} + /// Creates an async workflow from two workflows 'x' and 'y', mapping its results with 'f'. + /// Similar to map2 but workflows are run in parallel. + /// The mapping function. + /// First async workflow. + /// Second async workflow. + #if FABLE_COMPILER + let pmap2 f x y = map2 f x y + #else + let pmap2 f x y = async { + let! ct = Async.CancellationToken + let x = Async.StartImmediateAsTask (x, ct) + let y = Async.StartImmediateAsTask (y, ct) + let! x' = Async.AwaitTask x + let! y' = Async.AwaitTask y + return f x' y' } + #endif + + /// Creates an async workflow from three workflows 'x', 'y' and 'z', mapping its results with 'f'. + /// Similar to map3 but workflows are run in parallel. + /// The mapping function. + /// First async workflow. + /// Second async workflow. + /// third async workflow. + #if FABLE_COMPILER + let pmap3 f x y z = map3 f x y z + #else + let pmap3 f x y z = async { + let! ct = Async.CancellationToken + let x = Async.StartImmediateAsTask (x, ct) + let y = Async.StartImmediateAsTask (y, ct) + let z = Async.StartImmediateAsTask (z, ct) + let! x' = Async.AwaitTask x + let! y' = Async.AwaitTask y + let! z' = Async.AwaitTask z + return f x' y' z' } + #endif + /// Creates an async workflow from two workflows 'x' and 'y', tupling its results. let zip x y = async { let! a = x diff --git a/src/FSharpPlus/Extensions/Task.fs b/src/FSharpPlus/Extensions/Task.fs index b10569567..1b87d8653 100644 --- a/src/FSharpPlus/Extensions/Task.fs +++ b/src/FSharpPlus/Extensions/Task.fs @@ -134,6 +134,28 @@ module Task = ) |> ignore) |> ignore) |> ignore tcs.Task + /// Creates a task workflow from two workflows 'x' and 'y', mapping its results with 'f'. + /// Similar to map2 but workflows are run in parallel. + /// The mapping function. + /// First task workflow. + /// Second task workflow. + let pmap2 f x y = task { + let! x' = x + let! y' = y + return f x' y' } + + /// Creates a task workflow from three workflows 'x', 'y' and z, mapping its results with 'f'. + /// Similar to map2 but workflows are run in parallel. + /// The mapping function. + /// First task workflow. + /// Second task workflow. + /// Third task workflow. + let pmap3 f x y z = task { + let! x' = x + let! y' = y + let! z' = z + return f x' y' z' } + /// Creates a task workflow that is the result of applying the resulting function of a task workflow /// to the resulting value of another task workflow /// Task workflow returning a function diff --git a/src/FSharpPlus/Extensions/ValueTask.fs b/src/FSharpPlus/Extensions/ValueTask.fs index 1138bcf5b..669470975 100644 --- a/src/FSharpPlus/Extensions/ValueTask.fs +++ b/src/FSharpPlus/Extensions/ValueTask.fs @@ -62,6 +62,35 @@ module ValueTask = with e -> tcs.SetException e))) tcs.Task |> ValueTask<'W> + /// Creates a task workflow from two workflows 'x' and 'y', mapping its results with 'f'. + /// Similar to map2 but workflows are run in parallel. + /// The mapping function. + /// First ValueTask workflow. + /// Second ValueTask workflow. + /// Third ValueTask workflow. + let pmap2 (f: 'T -> 'U -> 'V) (x: ValueTask<'T>) (y: ValueTask<'U>) : ValueTask<'V> = + task { + let! x' = x + let! y' = y + return f x' y' + } + |> ValueTask<'V> + + /// Creates a ValueTask workflow from three workflows 'x', 'y' and z, mapping its results with 'f'. + /// Similar to map3 but workflows are run in parallel. + /// The mapping function. + /// First ValueTask workflow. + /// Second ValueTask workflow. + /// Third ValueTask workflow. + let pmap3 (f: 'T -> 'U -> 'V -> 'W) (x: ValueTask<'T>) (y: ValueTask<'U>) (z: ValueTask<'V>) : ValueTask<'W> = + task { + let! x' = x + let! y' = y + let! z' = z + return f x' y' z' + } + |> ValueTask<'W> + /// Creates a ValueTask workflow that is the result of applying the resulting function of a ValueTask workflow /// to the resulting value of another ValueTask workflow /// ValueTask workflow returning a function