-
Notifications
You must be signed in to change notification settings - Fork 22
Description
I propose we add syntax sugar to turn
let result =
for s with t in ts do
s + tinto
let result =
ts
|> #Collection.fold (fun s t -> s + t) sThe with keyword introduces the initial state, and the value inside the for expression is expected to be the same as the initial state.
The existing ways of approaching this problem in F# are
fold
Folds are widely used yet slightly unwieldy, especially for beginners but even for experienced users. Nested folds tend to get really messy if we aren't extra careful with formatting. There are also several ways to write them: (state, list) ||> fold f, list |> fold f state, fold f state list. Each style has its detractors, often not without good reason. Only the first offers type inference for both state and `list within the function, but is a somewhat obscure approach.
let rec f s ts = ...
Ad-hoc recursive functions are a bit verbose, so we don't use them unless we really need to.
let mutable s in for t in ts do s <- ...
Finally, there probably isn't anything wrong with using a mutable accumulator, but it's just not something people like to reach for because it feels icky.
Pros and Cons
The advantages of making this adjustment to F# are
- Conducive to useful type inference (because
sis specified prior to the function) - Much easier for new FP users to understand without sacrificing immutability
- Better legibility for experienced users in many situations, e.g. when nested
- Alleviate the need for closing brackets at the end of the
foldfunction or for trailing arguments, which tend to be a bit unsightly following longfuns - Natural addition to the
forloop
The disadvantages of making this adjustment to F# are
Yet more syntax to document and learn. On the other hand, it seems quite intuitive and hence easy to remember.
I don't think it should require any changes to the API for CEs, but I could be wrong.
Extra information
Estimated cost (XS, S, M, L, XL, XXL):
M (please correct me if I am wrong)
Related suggestions: (put links to related suggestions here)
Perhaps we can have a yield version that translates into a scan:
let results =
[ for s with t in ts do
yield s + t
]There is some slight ambiguity here, as yield is no longer a required keyword when the for is used in a sequence/list/array. Some users may expect for-with to behave as a scan even without the yield keyword if it is within a list.
Please let me know if I should open another issue for this suggestion, and I will update with the link here.
Affidavit (please submit!)
Please tick these items by placing a cross in the box:
- This is not a question (e.g. like one you might ask on StackOverflow) and I have searched StackOverflow for discussions of this issue
- This is a language change and not purely a tooling change (e.g. compiler bug, editor support, warning/error messages, new warning, non-breaking optimisation) belonging to the compiler and tooling repository
- This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it
- I have searched both open and closed suggestions on this site and believe this is not a duplicate
Please tick all that apply:
- This is not a breaking change to the F# language design
- I or my company would be willing to help implement and/or test this
For Readers
If you would like to see this issue implemented, please click the 👍 emoji on this issue. These counts are used to generally order the suggestions by engagement.