Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
semantics and exceptions. Its `tryFind`, `tryFindIndex` and `tryPick` return `voption`, `choose` and `tryPick` take
functions that return `voption`, and `groupBy`, `partition`, `partitionWith` and `zip` return struct tuples; the
`Parallel` modules of the `Option` and `Tuple` namespaces repeat them with options and reference tuples.
* `IndexedList` has every function of the FSharp.Core `List` module that applies to an immutable list, with its semantics,
parameter names and exceptions and with stable sorts, plus `binarySearch`, `binarySearchRange`,
`binarySearchRangeWithComparer`, `binarySearchWithComparer`, `blit`, `indexOf`, `indexOfRange`, `indexOfRangeWith`,
`indexOfWith`, `lastIndexOf`, `lastIndexOfRange`, `lastIndexOfRangeWith`, `lastIndexOfWith`, `ofReadOnlySpan`, `ofSpan`,
`removeMany`, `removeManyWith`, `revRange`, `skipLast`, `sortRange`, `sortRangeWith`, `sortRangeWithComparer`,
`sortWithComparer`, `sub`, `takeLast`, `tryFindIndexBackRange`, `tryFindIndexRange`, `tryUncons`, `uncons` and the struct
partial active patterns `Cons` and `Nil`.
* The functions of `IndexedList` that wrap a member of `ImmutableList<'T>` throw what the member throws, with the names of
their own parameters. `removeMany` removes one element for each value, in `EqualityComparer<'T>.Default`. The functions
that take a range check it before they call the member: the members accept a range whose end overflows `Int32.MaxValue`,
`BinarySearch` accepts a range beyond the end, and `LastIndexOf` and `FindLastIndex` accept a last element at or after
the end and answer with the index of another element.
A function that takes a sequence throws `ArgumentNullException` that names the parameter for a `null` sequence and for a
default `FlatList` given as a sequence, which the members would reject with `InvalidOperationException` while they
enumerate it; the `IIndexedList` and `IndexedListBuilder` modules and the `indexedList { }` expression do the same.
* `sortRange`, `sortRangeWith` and `sortRangeWithComparer` are stable, as the other sorts of `IndexedList` are, and do not
wrap the unstable `ImmutableList<'T>.Sort(index, count, comparer)`.
* The `IIndexedList` module has the functions of `IndexedList` for `IImmutableList<'T>`, without the creation and builder
functions, `binarySearch*`, `blit`, `revRange`, `sortRange*`, `sub` and `tryFindIndex*Range`, plus `clear`. Its functions
keep the implementation of the input list where the result has the element type of the input, and return an
`IndexedList` otherwise. `IIndexedList<'T>` is the abbreviation of `IImmutableList<'T>`, as `IndexedList<'T>` is the
abbreviation of `ImmutableList<'T>`.
* `max`, `maxBy`, `min` and `minBy` of `IndexedList` and `IIndexedList` are inline, as the ones of `List` are, so that the
comparison is compiled for the type of the elements and boxes nothing. `exists2`, `forall2` and `compareWith` stop at the
first pair that decides. `concat` and `collect` share the nodes of an indexed list of at least 16 elements instead of
copying its elements, and `skip`, `take`, `sub`, `splitAt`, `chunkBySize`, `windowed` and the range sorts read a range in
O(log n + count).
* The `FSharp.Collections.Immutable.Option` and `FSharp.Collections.Immutable.Tuple` namespaces have `IndexedList` and
`IIndexedList` modules that repeat the functions that use value options or struct tuples with options and reference
tuples.
* The `IndexedListBuilder` module works on the builder of an indexed list, and `indexedList { }` builds an indexed list.
The module removes and replaces values (`remove`, `removeWith`, `removeAll`, `removeMany`, `removeManyAt`,
`removeManyWith`, `replace`, `replaceWith`), inserts values (`insertManyAt`), reverses, sorts and searches ranges
(`revRange`, `sortRange`, `sortRangeWith`, `sortRangeWithComparer`, `indexOfRange`, `indexOfRangeWith`,
`lastIndexOfRange`, `lastIndexOfRangeWith`, `binarySearch`, `binarySearchWithComparer`,
`binarySearchRangeWithComparer`) and copies elements into an array (`blit`). `replace` throws `ArgumentException` for a
value that no element equals, as the builder of an indexed list does.

### Changed

Expand All @@ -44,6 +81,49 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* `FlatList.sub` has the meaning of `Array.sub`: `sub array startIndex count` returns `count` elements from `startIndex`.
It was `sub start stop list`.
* The nested `FlatList.Builder` module is now the `FlatListBuilder` module.
* The `ImmutableList` module is `IndexedList`. It works on `ImmutableList<'T>` (`IndexedList<'T>`), where most functions of
1.0.0 took any `IImmutableList<'T>` and the ones that change a list returned an `IImmutableList<'T>`; the functions for
`IImmutableList<'T>` are in the new `IIndexedList` module. 1.0.0 compiled the module as `ImmutableListModule`, with the
F# names of its functions, such as `isEmpty`, and `IndexedList` compiles them to PascalCase names, such as `IsEmpty`.
* `IndexedList.ofList` takes an F# list, where `ofList` took any sequence. The mapping of `collect` returns an indexed
list and `concat` takes indexed lists, where they took any sequences. `append` takes two indexed lists, where it took a
list and a sequence: `append list (ofSeq items)` or `insertManyAt (length list) items list` appends a sequence.
* `IndexedList`: `tryFind`, `tryFindIndex`, `tryHead`, `tryItem`, `tryLast` and `tryTail` return `voption`; `choose` and
`pick` take choosers that return `voption`; `splitAt` returns a struct tuple; and the generator of `unfold` returns a
`voption` of a struct tuple with the element before the state, as in `List.unfold`, where it returned an `option` of a
tuple with the state before the element.
* `IndexedList`: every function throws what the FSharp.Core `List` function of the same name throws, and names the
parameters of `List`, such as `source` in `ofSeq`, `itemsToExclude` in `except` and `list1` in `append`. `head`, `last`
and `tail` of an empty list, and `item` and `removeAt` for an index outside the list, throw `ArgumentException`, where
they threw `ArgumentOutOfRangeException`. `take` and `splitAt` throw `InvalidOperationException` for a count beyond the
length and `ArgumentException` for a negative count, and `skip` and `truncate` return the list and an empty list for a
negative count, where all four threw `ArgumentOutOfRangeException`. `forall2` throws `ArgumentException` for lists of
different lengths when every pair of the shorter list satisfies the predicate, where it returned `true`. `contains` and
`ofBuilder` throw `ArgumentNullException` for a `null` input, where they threw `NullReferenceException`. A default
`FlatList` given as a sequence to `ofSeq`, `concat` and `except` throws `ArgumentNullException`, where it threw
`InvalidOperationException` (`except` of an empty list returned).
* `IndexedList.skipWhile` and `takeWhile` do what their names say, as the functions of `List` do. In 1.0.0, `skipWhile`
returned the elements before the first one that fails the predicate, and `takeWhile` returned the elements from it on.
* `IndexedList.except` removes every element equal to an excluded item and the duplicates of the other elements, as
`List.except` does, where the 1.0.0 `except` removed one element for each item, as `removeMany` does now.
* `IndexedList.contains` compares in F# structural equality, where 1.0.0 compared in `EqualityComparer<'T>.Default`:
arrays with equal elements are equal, and `nan` is not equal to itself. `remove` and `replace`, and `indexOf`,
`lastIndexOf`, `indexOfRange` and `lastIndexOfRange`, which replace `index`, `lastIndex`, `indexRange` and
`lastIndexRange`, compare in `EqualityComparer<'T>.Default`, where 1.0.0 compared in F# structural equality
(`HashIdentity.Structural`), so elements that are arrays, or whose type defines `Equals` differently from F# equality,
compare differently.
* The functions that replace renamed functions of 1.0.0 differ from them in these cases. `insertAt`, `insertManyAt` and
`updateAt` throw `ArgumentException` for an index outside the list, where `insert`, `insertRange` and `withItem` threw
`ArgumentOutOfRangeException`. `removeManyAt` throws `ArgumentException` for a range that is not inside the list and
removes nothing for a negative count or a range whose end overflows `Int32.MaxValue`, where `removeRange` threw
`ArgumentOutOfRangeException`. `lastIndexOf` returns -1 for an empty list, where `lastIndex` threw
`ArgumentOutOfRangeException`. `lastIndexOfRange` throws `ArgumentOutOfRangeException` for a start index at or after the
end of the list, where `lastIndexRange` accepted it and could answer with an index that the list does not have. `rev`
and `revRange` throw `ArgumentNullException` for a `null` list, where `reverse` and `reverseRange` threw
`NullReferenceException`.
* `IndexedList.rev` builds the reversed list from a reversed copy of the elements. At 100 000 integers it takes about 3 ms
where `reverse`, which called `ImmutableList.Reverse`, took about 23 ms, and it allocates 5.2 MB where `reverse`
allocated 4.8 MB.

### Removed

Expand All @@ -61,6 +141,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
compared in F# structural equality. The removed functions did not remove the elements that satisfy a predicate: use
`filter` with the negated predicate for that.
* `FlatList.removeRange`: use `removeManyAt`.
* The functions of the `ImmutableList` module that `IndexedList` has under another name and with the same arguments:
`lastIndex` to `lastIndexOf`, `lastIndexWith` to `lastIndexOfWith`, `indexRange` to `indexOfRange`, `indexRangeWith` to
`indexOfRangeWith`, `lastIndexRange` to `lastIndexOfRange`, `lastIndexRangeWith` to `lastIndexOfRangeWith`, `insert` to
`insertAt`, `insertRange` to `insertManyAt`, `removeRange` to `removeManyAt`, `exceptWith` to `removeManyWith`, `reverse`
to `rev`, `reverseRange` to `revRange` and `withItem` to `updateAt`. Only `revRange index count list` differs: it takes
the index and the count as two arguments, where `reverseRange` took them as a tuple.
* `ImmutableList.index` and `indexWith`: use `IndexedList.indexOf` and `indexOfWith`. `ImmutableList.indexFrom`,
`indexFromWith`, `lastIndexFrom` and `lastIndexFromWith`: use `IndexedList.indexOfRange`, `indexOfRangeWith`,
`lastIndexOfRange` and `lastIndexOfRangeWith`. `indexFrom index item list` is
`indexOfRange index (length list - index) item list`, and `lastIndexFrom index item list` is
`lastIndexOfRange index (index + 1) item list`. `index`, `indexWith`, `indexFrom` and `indexFromWith` returned a function
that took the list a second time, as in `index item list list`; the functions that replace them return the index.
* `ImmutableList.clear`: use `IndexedList.empty`, or `IIndexedList.clear` to keep the implementation of an interface value.
* `ImmutableList.skipUntil` and `takeUntil`: use `IndexedList.skipWhile` and `takeWhile` with the negated predicate. They
returned each other's result in 1.0.0: `skipUntil p list` returned what `takeWhile (not << p) list` returns, and
`takeUntil p list` returned what `skipWhile (not << p) list` returns.
* `ImmutableList.filterFold`: it has no replacement.
* The `IndexedSeq` module and the `IIndexedSeq<'T>` abbreviation of `IReadOnlyList<'T>`: use `IReadOnlyList<'T>`, whose
`Count` and indexer replace `IndexedSeq.length` and `IndexedSeq.item`. `IndexedSeq.check` needs no replacement, because
every function of the list modules throws `ArgumentNullException` for a `null` list.

## [1.0.0] - 2020-02-23

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ Please also join the [F# Open Source Group](http://fsharp.github.com)
| Module | .NET type | Computation expression |
|---|---|---|
| `FlatList` | `ImmutableArray<'T>` | `flatList { }` |
| `ImmutableList` | `ImmutableList<'T>` | – |
| `IndexedList` | `ImmutableList<'T>` | `indexedList { }` |
| `IIndexedList` | `IImmutableList<'T>` | – |
| `Stack` | `ImmutableStack<'T>` | – |
| `Queue` | `ImmutableQueue<'T>` | – |
| `HashMap` | `ImmutableDictionary<'Key, 'Value>` | – |
| `SortedMap` | `ImmutableSortedDictionary<'Key, 'Value>` | – |
| `HashSet` | `ImmutableHashSet<'T>` | – |
| `SortedSet` | `ImmutableSortedSet<'T>` | – |
| `IIndexedSeq` | `IReadOnlyList<'T>` | – |

[Documentation](https://fsprojects.github.io/FSharp.Collections.Immutable/)

Expand Down
4 changes: 2 additions & 2 deletions docsSrc/Explanations/Background.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ While F# has its own built-in immutable collections, System.Collections.Immutabl
| Module | .NET type | Computation expression |
|---|---|---|
| `FlatList` | `ImmutableArray<'T>` | `flatList { }` |
| `ImmutableList` | `ImmutableList<'T>` | – |
| `IndexedList` | `ImmutableList<'T>` | `indexedList { }` |
| `IIndexedList` | `IImmutableList<'T>` | – |
| `Stack` | `ImmutableStack<'T>` | – |
| `Queue` | `ImmutableQueue<'T>` | – |
| `HashMap` | `ImmutableDictionary<'Key, 'Value>` | – |
| `SortedMap` | `ImmutableSortedDictionary<'Key, 'Value>` | – |
| `HashSet` | `ImmutableHashSet<'T>` | – |
| `SortedSet` | `ImmutableSortedSet<'T>` | – |
| `IIndexedSeq` | `IReadOnlyList<'T>` | – |

---

Expand Down
2 changes: 1 addition & 1 deletion docsSrc/Tutorials/Getting_Started.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ open FSharp.Collections.Immutable

``` F#
// Create an immutable list
let list1 = ImmutableList.ofSeq [1; 2; 3]
let list1 = IndexedList.ofSeq [1; 2; 3]

// Create an immutable hash set
let set1 = HashSet.ofSeq ["a"; "b"]
Expand Down
4 changes: 2 additions & 2 deletions docsSrc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ F# bindings for [System.Collections.Immutable](https://learn.microsoft.com/en-us
| Module | .NET type | Computation expression |
|---|---|---|
| `FlatList` | `ImmutableArray<'T>` | `flatList { }` |
| `ImmutableList` | `ImmutableList<'T>` | – |
| `IndexedList` | `ImmutableList<'T>` | `indexedList { }` |
| `IIndexedList` | `IImmutableList<'T>` | – |
| `Stack` | `ImmutableStack<'T>` | – |
| `Queue` | `ImmutableQueue<'T>` | – |
| `HashMap` | `ImmutableDictionary<'Key, 'Value>` | – |
| `SortedMap` | `ImmutableSortedDictionary<'Key, 'Value>` | – |
| `HashSet` | `ImmutableHashSet<'T>` | – |
| `SortedSet` | `ImmutableSortedSet<'T>` | – |
| `IIndexedSeq` | `IReadOnlyList<'T>` | – |

---

Expand Down
2 changes: 2 additions & 0 deletions src/FSharp.Collections.Immutable/ComputationExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ module FSharp.Collections.Immutable.ComputationExpressions
// ---- Creation ----

let flatList = FlatListCE ()

let indexedList = IndexedListCE ()
14 changes: 14 additions & 0 deletions src/FSharp.Collections.Immutable/ComputationExpressions.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,17 @@ module FSharp.Collections.Immutable.ComputationExpressions
/// Evaluates to a flat list of 0, 1, 4, 9, 100 and 200.
/// </example>
val flatList : FlatListCE

/// <summary>Builds an indexed list.</summary>
/// <example id="indexedList-1">
/// <code lang="fsharp">
/// let squares = indexedList {
/// yield 0
/// for i in 1..3 do
/// yield i * i
/// yield! [ 100; 200 ]
/// }
/// </code>
/// Evaluates to an indexed list of 0, 1, 4, 9, 100 and 200.
/// </example>
val indexedList : IndexedListCE
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@
<Compile Include="Helper\ArrayChecks.fs" />
<Compile Include="Helper\Arrays.fs" />
<Compile Include="Helper\ParallelArrays.fs" />
<Compile Include="Helper\ListChecks.fs" />
<Compile Include="Helper\ListArrays.fs" />
<Compile Include="Helper\Snapshot.fs" />
<Compile Include="Helper\Collectors.fs" />
<Compile Include="Helper\Lengths.fs" />
<Compile Include="Helper\DescendingSorts.fs" />
<Compile Include="Helper\ListRanges.fs" />
<Compile Include="FlatList\FlatListTypes.fs" />
<Compile Include="FlatList\FlatList.fsi" />
<Compile Include="FlatList\FlatList.fs" />
Expand All @@ -44,10 +51,25 @@
<Compile Include="FlatList\FlatListBuilder.fs" />
<Compile Include="FlatList\FlatListCE.fsi" />
<Compile Include="FlatList\FlatListCE.fs" />
<Compile Include="IndexedList\IndexedListTypes.fs" />
<Compile Include="IndexedList\IndexedList.fsi" />
<Compile Include="IndexedList\IndexedList.fs" />
<Compile Include="IndexedList\IndexedListOption.fsi" />
<Compile Include="IndexedList\IndexedListOption.fs" />
<Compile Include="IndexedList\IndexedListTuple.fsi" />
<Compile Include="IndexedList\IndexedListTuple.fs" />
<Compile Include="IndexedList\IIndexedList.fsi" />
<Compile Include="IndexedList\IIndexedList.fs" />
<Compile Include="IndexedList\IIndexedListOption.fsi" />
<Compile Include="IndexedList\IIndexedListOption.fs" />
<Compile Include="IndexedList\IIndexedListTuple.fsi" />
<Compile Include="IndexedList\IIndexedListTuple.fs" />
<Compile Include="IndexedList\IndexedListBuilder.fsi" />
<Compile Include="IndexedList\IndexedListBuilder.fs" />
<Compile Include="IndexedList\IndexedListCE.fsi" />
<Compile Include="IndexedList\IndexedListCE.fs" />
<Compile Include="Stack.fs" />
<Compile Include="ImmutableList.fs" />
<Compile Include="Queue.fs" />
<Compile Include="IndexedSeq.fs" />
<Compile Include="Maps.fs" />
<Compile Include="Sets.fs" />
<Compile Include="ComputationExpressions.fsi" />
Expand Down
Loading
Loading