From 93949d817bf458eb752be2918a6878236912c20a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Oct 2025 14:55:17 +0000 Subject: [PATCH 1/4] Initial plan From a0a08edaa661acc6b65d84a902dd8ea9dbe40aaf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:00:47 +0000 Subject: [PATCH 2/4] Add applicative computation expressions documentation to and! section Co-authored-by: BillWagner <493969+BillWagner@users.noreply.github.com> --- .../language-reference/computation-expressions.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/fsharp/language-reference/computation-expressions.md b/docs/fsharp/language-reference/computation-expressions.md index 3f55adca0cfb8..6cc9627e746cf 100644 --- a/docs/fsharp/language-reference/computation-expressions.md +++ b/docs/fsharp/language-reference/computation-expressions.md @@ -80,7 +80,7 @@ If you bind the call to a computation expression with `let`, you will not get th ### `and!` -The `and!` keyword allows you to bind the results of multiple computation expression calls in a performant manner. +The `and!` keyword allows you to bind the results of multiple computation expression calls in a performant manner. This keyword enables **applicative computation expressions**, which provide a different computational model from the standard monadic approach. ```fsharp let doThingsAsync url = @@ -92,12 +92,20 @@ let doThingsAsync url = } ``` -Using a series of `let! ... let! ...` forces re-execution of expensive binds, so using `let! ... and! ...` should be used when binding the results of numerous computation expressions. +Using a series of `let! ... let! ...` forces sequential execution where each bind depends on the previous one. In contrast, `let! ... and! ...` indicates that the computations are independent of each other. This independence allows computation expression authors to: + +- Execute computations more efficiently +- Potentially run computations in parallel +- Accumulate results without forcing unnecessary sequential dependencies + +The restriction is that computations combined with `and!` cannot depend on the results of previously bound values within the same `let!`/`and!` chain. This trade-off enables the performance benefits. `and!` is defined primarily by the `MergeSources(x1, x2)` member on the builder type. Optionally, `MergeSourcesN(x1, x2 ..., xN)` can be defined to reduce the number of tupling nodes, and `BindN(x1, x2 ..., xN, f)`, or `BindNReturn(x1, x2, ..., xN, f)` can be defined to bind computation expression results efficiently without tupling nodes. +For more information on applicative computation expressions, see [Applicative Computation Expressions in F# 5](../whats-new/fsharp-50.md#applicative-computation-expressions) and [F# RFC FS-1063](https://github.com/fsharp/fslang-design/blob/main/FSharp-5.0/FS-1063-support-letbang-andbang-for-applicative-functors.md). + ### `do!` The `do!` keyword is for calling a computation expression that returns a `unit`-like type (defined by the `Zero` member on the builder): From dad790e158a4a6917469d02b4e2498953ee56714 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 7 Oct 2025 09:13:07 -0400 Subject: [PATCH 3/4] Update docs/fsharp/language-reference/computation-expressions.md --- docs/fsharp/language-reference/computation-expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fsharp/language-reference/computation-expressions.md b/docs/fsharp/language-reference/computation-expressions.md index 6cc9627e746cf..0e371b84446e9 100644 --- a/docs/fsharp/language-reference/computation-expressions.md +++ b/docs/fsharp/language-reference/computation-expressions.md @@ -80,7 +80,7 @@ If you bind the call to a computation expression with `let`, you will not get th ### `and!` -The `and!` keyword allows you to bind the results of multiple computation expression calls in a performant manner. This keyword enables **applicative computation expressions**, which provide a different computational model from the standard monadic approach. +The `and!` keyword allows you to bind the results of multiple computation expression calls in a performant manner. This keyword enables *applicative computation expressions*, which provide a different computational model from the standard monadic approach. ```fsharp let doThingsAsync url = From b4cc422582bfe69c4c436186cf86cda812acf80f Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 7 Oct 2025 09:21:50 -0400 Subject: [PATCH 4/4] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../language-reference/computation-expressions.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/fsharp/language-reference/computation-expressions.md b/docs/fsharp/language-reference/computation-expressions.md index 0e371b84446e9..75d668b36d595 100644 --- a/docs/fsharp/language-reference/computation-expressions.md +++ b/docs/fsharp/language-reference/computation-expressions.md @@ -80,7 +80,7 @@ If you bind the call to a computation expression with `let`, you will not get th ### `and!` -The `and!` keyword allows you to bind the results of multiple computation expression calls in a performant manner. This keyword enables *applicative computation expressions*, which provide a different computational model from the standard monadic approach. +The `and!` keyword allows you to bind the results of multiple computation expression calls more efficiently. This keyword enables *applicative computation expressions*, which provide a different computational model from the standard monadic approach. ```fsharp let doThingsAsync url = @@ -92,11 +92,11 @@ let doThingsAsync url = } ``` -Using a series of `let! ... let! ...` forces sequential execution where each bind depends on the previous one. In contrast, `let! ... and! ...` indicates that the computations are independent of each other. This independence allows computation expression authors to: +Using a series of `let! ... let! ...` executes the computations sequentially, even if they are independent. In contrast, `let! ... and! ...` indicates that the computations are independent, allowing applicative combination. This independence allows computation expression authors to: -- Execute computations more efficiently -- Potentially run computations in parallel -- Accumulate results without forcing unnecessary sequential dependencies +- Execute computations more efficiently. +- Can run computations in parallel. +- Accumulate results without unnecessary sequential dependencies. The restriction is that computations combined with `and!` cannot depend on the results of previously bound values within the same `let!`/`and!` chain. This trade-off enables the performance benefits.