@@ -178,17 +178,36 @@ functions and that the override functions are equivalent to the defaults after c
178178### D9. Delivery: one pull request per collection, stacked
179179
180180` chore/foundation ` (helper module, order check script, test categories and contract bases, changelog and documentation
181- skeleton, target frameworks), then ` feat/flat-list ` , ` feat/indexed-list ` , ` feat/queue ` , ` feat/stack ` , ` feat/hash-map ` (with
182- ` IMap ` ), ` feat/sorted-map ` , ` feat/hash-set ` (with ` ISet ` ), ` feat/sorted-set ` , ` feat/frozen-map ` , ` feat/frozen-set ` , and an
183- optional ` chore/benchmarks ` (BenchmarkDotNet, excluded from the solution filter). Each pull request deletes the legacy file
181+ skeleton, target frameworks), then ` feat/flat-list ` , ` feat/flat-list-parallel ` (the nested ` Parallel ` module of D11),
182+ ` feat/indexed-list ` , ` feat/queue ` , ` feat/stack ` , ` feat/hash-map ` (with ` IMap ` ), ` feat/sorted-map ` , ` feat/hash-set ` (with
183+ ` ISet ` ), ` feat/sorted-set ` , ` feat/frozen-map ` , ` feat/frozen-set ` (both with the alternate lookup of D11), and an optional
184+ ` chore/benchmarks ` (BenchmarkDotNet, excluded from the solution filter). Each pull request deletes the legacy file
184185it replaces, keeps the build green and updates the changelog and the documentation table. No release is cut mid-chain.
185186
186187### D10. Target frameworks
187188
188189` net8.0;net10.0 ` . The published package already targeted ` net8.0 ` only; ` netstandard2.0 ` is not added (the LINQ surface
189190used in D5 would need conditional fallbacks); ` net9.0 ` is not added (short-term support, ended 2026-05; the ` net8.0 ` asset
190- serves it). ` net10.0 ` enables ` #if NET10_0_OR_GREATER ` paths for newer LINQ members and, as a follow-up, the Frozen
191- alternate lookup.
191+ serves it). ` net10.0 ` enables ` #if NET10_0_OR_GREATER ` paths for newer LINQ members and the Frozen alternate lookup (D11).
192+
193+ ### D11. ` FlatList.Parallel ` and the Frozen alternate lookup
194+
195+ ` FlatList ` gets a nested module ` Parallel ` that mirrors ` Array.Parallel ` through the zero-copy bridge of D5: every function
196+ unwraps the array, calls ` Array.Parallel.* ` and wraps the fresh result (` map ` , ` mapi ` , ` choose ` , ` collect ` , ` filter ` , ` init ` ,
197+ ` iter ` , ` iteri ` , ` zip ` , ` groupBy ` , ` partition ` , ` partitionWith ` , ` sort ` , ` sortBy ` , ` sortByDescending ` , ` sortDescending ` ,
198+ ` sortWith ` , ` reduce ` , ` reduceBy ` , ` sum ` , ` sumBy ` , ` average ` , ` averageBy ` , ` max ` , ` maxBy ` , ` min ` , ` minBy ` , ` exists ` , ` forall ` ,
199+ ` tryFind ` , ` tryFindIndex ` , ` tryPick ` ); the three ` sortInPlace* ` functions are omitted because they mutate. The nested module
200+ lives in ` FlatList.fsi ` /` FlatList.fs ` (as ` Array.Parallel ` lives in ` array.fs ` ) with its own category banners, and has its
201+ ` Option ` and ` Tuple ` counterparts (` choose ` , ` tryFind ` , ` tryFindIndex ` , ` tryPick ` ; ` groupBy ` , ` partition ` , ` partitionWith ` ,
202+ ` zip ` ). Its tests compare every function with the sequential ` FlatList ` counterpart on the same inputs.
203+
204+ ` FrozenMap ` and ` FrozenSet ` expose ` alternateLookup<'Alternate> ` (` GetAlternateLookup ` ) and ` tryAlternateLookup<'Alternate> `
205+ (` TryGetAlternateLookup ` , returning ` voption ` ) under ` #if NET10_0_OR_GREATER ` , because the API exists only in the ` net9.0 `
206+ and later assets of the package. They return the BCL ` AlternateLookup<'Alternate> ` struct; callers with a
207+ ` ReadOnlySpan<char> ` alternate use its ` ContainsKey ` /` TryGetValue ` /` Contains ` members directly, since F# cannot instantiate
208+ its own generic functions with byref-like type arguments, so no ` findAlternate ` -style wrappers are added. The comparer must
209+ implement ` IAlternateEqualityComparer<'Alternate, 'Key> ` (as ` StringComparer.Ordinal ` does); ` tryAlternateLookup ` returns
210+ ` ValueNone ` otherwise. The tests for these functions compile only for ` net10.0 ` .
192211
193212## Consequences
194213
@@ -338,6 +357,12 @@ their element-type-changing transformations return the concrete type.
338357| ** Type-specific** | | | | | | | | | |
339358| ` clear ` | | – | – | ᵇ | – | ᵇ | – | ᵇ | keeps the implementation |
340359| ` isDefault ` / ` isDefaultOrEmpty ` | | ᵇ | – | – | – | – | – | – | accept a default ` FlatList ` |
360+ | ** Parallel** (nested module ` FlatList.Parallel ` , mirrors ` Array.Parallel ` ; same category order inside) | | | | | | | | | |
361+ | ` average ` / ` averageBy ` / ` max ` / ` maxBy ` / ` min ` / ` minBy ` / ` reduce ` / ` reduceBy ` / ` sum ` / ` sumBy ` | | ✓ | – | – | – | – | – | – | Folding |
362+ | ` choose ` / ` collect ` / ` filter ` / ` init ` / ` iter ` / ` iteri ` / ` map ` / ` mapi ` / ` zip ` | Ⓥ (` choose ` ), Ⓣ (` zip ` ) | ✓ | – | – | – | – | – | – | Transformation (` init ` : Creation) |
363+ | ` exists ` / ` forall ` / ` tryFind ` / ` tryFindIndex ` / ` tryPick ` | Ⓥ (` try* ` ) | ✓ | – | – | – | – | – | – | Search |
364+ | ` groupBy ` / ` partition ` / ` partitionWith ` | Ⓣ | ✓ | – | – | – | – | – | – | Partitioning and grouping |
365+ | ` sort ` / ` sortBy ` / ` sortByDescending ` / ` sortDescending ` / ` sortWith ` | | ✓ | – | – | – | – | – | – | Sorting; ` sortInPlace* ` omitted |
341366
342367` Option.* ` : ` choose ` , ` pick ` , ` tryExactlyOne ` , ` tryFind ` , ` tryFindBack ` , ` tryFindIndex ` , ` tryFindIndexBack ` , ` tryHead ` ,
343368` tryItem ` , ` tryLast ` , ` tryPick ` , ` tryTail ` , ` tryUncons ` , ` unfold ` .
@@ -391,6 +416,9 @@ their element-type-changing transformations return the concrete type.
391416| ` partition ` | Ⓣ | ✓ | ✓ | ✓ | ✓ | |
392417| ** Conversion** | | | | | | |
393418| ` toArray ` / ` toList ` / ` toSeq ` | Ⓣ | ✓ | ✓ | ✓ | ✓ | ` struct ('Key * 'Value) ` |
419+ | ** Type-specific** | | | | | | |
420+ | ` alternateLookup<'Alternate> ` | | – | – | – | ᵇ | ` GetAlternateLookup ` ; ` #if NET10_0_OR_GREATER ` |
421+ | ` tryAlternateLookup<'Alternate> ` | Ⓥ | – | – | – | ᵇ | ` TryGetAlternateLookup ` ; ` #if NET10_0_OR_GREATER ` |
394422
395423` Option.* ` : ` change ` , ` choose ` , ` pick ` , ` tryFind ` , ` tryFindKey ` , ` tryGetKey ` , ` tryPick ` . ` Tuple.* ` : ` addRange ` , ` ofArray ` ,
396424` ofList ` , ` ofSeq ` , ` ofSeqWithKeyComparer ` , ` partition ` , ` toArray ` , ` toList ` , ` toSeq ` (+ ` maxKeyValue ` , ` minKeyValue ` for
@@ -436,5 +464,8 @@ their element-type-changing transformations return the concrete type.
436464| ** Conversion** | | | | | | |
437465| ` toArray ` / ` toList ` / ` toSeq ` | | ✓ | ✓ | ✓ | ✓ | |
438466| ` toFlatList ` | | – | – | – | ᵇ | O(1) via ` Items ` |
467+ | ** Type-specific** | | | | | | |
468+ | ` alternateLookup<'Alternate> ` | | – | – | – | ᵇ | ` GetAlternateLookup ` ; ` #if NET10_0_OR_GREATER ` |
469+ | ` tryAlternateLookup<'Alternate> ` | Ⓥ | – | – | – | ᵇ | ` TryGetAlternateLookup ` ; ` #if NET10_0_OR_GREATER ` |
439470
440471` Option.* ` : ` choose ` , ` tryGetValue ` (+ ` tryItem ` for ` SortedSet ` ). ` Tuple.* ` : ` partition ` , ` partitionWith ` .
0 commit comments