You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: RFCs/FS-1152-For-loop-with-accumulation.md
+27-7Lines changed: 27 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,8 +1,3 @@
1
-
To do:
2
-
- Justification of the fundamentality of folds by counting usage - why improve folds specifically?
3
-
- More on dismissing CE alternative
4
-
- Looks too similar to a for loop?
5
-
6
1
# F# RFC FS-1152 - Fold loops
7
2
8
3
The design suggestion ["for-with" syntactic sugar for folds](https://github.com/fsharp/fslang-suggestions/issues/1362) has not yet been marked "approved in principle".
@@ -25,6 +20,23 @@ Extending the `for <pat> in <expr> do` syntax, a new optional clause with an acc
25
20
26
21
# Motivation
27
22
23
+
Why `fold`s in particular instead of coming up with a proposal that improves on more collection functions? Let's see how much `fold` is used compared to other collection functions:
24
+
-`map`: [176k files](https://github.com/search?type=code&q=language%3Afsharp+map) (includes the `Map` type)
`fold` stands out in terms of actual usage - and yet it has an abysmal syntax. Other highly common functions like `map`, `choose`, `collect` already have a nice syntax, and yet `fold` does not.
37
+
38
+
Moreover, `fold` is a fundamental operation in pure functional programming because it is a general-purpose function that can define many other collection functions like `map`, `reduce`, and `choose`, just like how `iter` corresponds to the imperative `for` loop. This suggests an opportunity to improve on the usage of `fold`s to make them palatable.
39
+
28
40
Let's start with how this is used in practice - the summarization of a sequence into a value, aka the fold operation, compared across different language features.
29
41
30
42
```fs
@@ -346,9 +358,17 @@ let sum xs = fold 0 { for x in xs -> (+) x } // variation 1
346
358
let sum xs = fold 0 { for acc, x in xs -> acc + x } // variation 2
347
359
let sum xs = fold { for acc, x in 0, xs -> acc + x } // variation 3
348
360
```
349
-
Generally, computation expressions have hard to understand error messages for overloaded computation expression methods and are are [notoriously difficult to debug](https://github.com/dotnet/fsharp/issues/13342). These are fixable with enough investments in CEs.
361
+
The variations that abuse tuple syntax don't help diagnose tuple ordering or placement.
362
+
363
+
One can even argue that computation expressions offer the opportunity to not just improve on folds but also other forms like `reduce` and `scan`, with support for custom operation keywords:
364
+
```fs
365
+
let sum xs = fold 0 { for x in xs -> accumulator + x } // 'accumulator' being a custom operation keyword
366
+
```
367
+
This specific example does not play well with tuple accumulators unless F# adds tuple member access by index.
368
+
369
+
Generally, computation expressions have hard to understand error messages for overloaded computation expression methods and are are [notoriously difficult to debug](https://github.com/dotnet/fsharp/issues/13342). These are fixable with enough investments in CEs, but the Microsoft F# team size got reduced from 6 to 2 + Copilot on March 2025, this work takes much much longer than just adding a `with` clause to `for` loops.
350
370
351
-
What's unfixable is the non-orthogonality to an existing computation expression context unlike the for loop which allows `yield` inside to yield to an outer list expression instead of being limited by a fold CE. Moreover, CEs also show a heavily different syntax compared to for loops and folds which add hinderance to understanding - each CE usage requires following CE methods which add indirection to understanding, only hiding large chunks of logic like `async` or `task` should worth CE usage. It would be much simpler to just write the underlying code (this critique also applies to `option` and `result` CEs for example). Since folds are so common in pure functional programming, they deserve a simple-to-use syntax as fold loops provide, instead of tucked away in hard-to-understand CE syntax.
371
+
What's unfixable is that CEs also show a heavily different syntax compared to `for` loops and folds which add hinderance to understanding - each CE usage requires following CE methods which add indirection to understanding, only hiding large chunks of logic like `async` or `task` should worth CE usage. It would be much simpler to just write the underlying code (this critique also applies to `option` and `result` CEs for example). Since folds are so common in pure functional programming, they deserve a simple-to-use syntax as fold loops provide, instead of tucked away in hard-to-understand CE syntax.
0 commit comments