From 6c866271d03287cbbb4198c23e0bfda2d0448a3d Mon Sep 17 00:00:00 2001 From: Devin Lyons Date: Mon, 21 Oct 2024 13:11:05 -0800 Subject: [PATCH] Incorporate feedback. --- src/FSharpPlus/Data/NonEmptyList.fs | 119 ++++++++++++++++++++++------ src/FSharpPlus/Data/NonEmptySeq.fs | 95 +++++++++++++++++----- 2 files changed, 172 insertions(+), 42 deletions(-) diff --git a/src/FSharpPlus/Data/NonEmptyList.fs b/src/FSharpPlus/Data/NonEmptyList.fs index b5bdc4611..f4e4487b9 100644 --- a/src/FSharpPlus/Data/NonEmptyList.fs +++ b/src/FSharpPlus/Data/NonEmptyList.fs @@ -199,7 +199,6 @@ module NonEmptyList = /// The first input list. /// The second input list. /// The resulting list of pairs. - let inline allPairs (list1: NonEmptyList<'T>) (list2: NonEmptyList<'U>) = Seq.allPairs list1 list2 |> ofSeq /// Concatenates two lists. @@ -218,7 +217,8 @@ module NonEmptyList = /// The function to transform the list elements into the type to be averaged. /// The input list. /// The resulting average. - let inline averageBy (projection: 'T -> ^U) (list: NonEmptyList<'T>) = List.averageBy projection (list.Head :: list.Tail) + let inline averageBy (projection: 'T -> ^U) (list: NonEmptyList<'T>) = + Seq.averageBy projection list /// /// Applies a function to each element in a list and then returns a list of values v where the applied function returned Some(v). @@ -226,7 +226,8 @@ module NonEmptyList = /// The function to be applied to the list elements. /// The input list. /// The resulting list comprising the values v where the chooser function returned Some(x). - let inline choose chooser (list: NonEmptyList<'T>) = list |> Seq.choose chooser |> ofSeq + let inline tryChoose chooser (list: NonEmptyList<'T>) = + list |> Seq.choose chooser |> List.ofSeq /// /// Applies a function to each element in a list and then returns a list of values v where the applied function returned Some(v). @@ -234,29 +235,32 @@ module NonEmptyList = /// The function to be applied to the list elements. /// The input list. /// The resulting list comprising the values v where the chooser function returned Some(x). - let inline tryChoose chooser (list: NonEmptyList<'T>) = list |> Seq.choose chooser |> List.ofSeq + /// Thrown when the chooser function returns None for all elements. + let inline choose chooser (list: NonEmptyList<'T>) = + tryChoose chooser list |> ofList /// Divides the input list into lists (chunks) of size at most chunkSize. /// Returns a new list containing the generated lists (chunks) as its elements. /// The maximum size of each chunk. /// The input list. /// The list divided into chunks. - let inline chunkBySize chunkSize (list: NonEmptyList<'T>) = - list.Head :: list.Tail |> List.chunkBySize chunkSize |> List.map ofList + let inline chunkBySize chunkSize (list: NonEmptyList<'T>): NonEmptyList> = + list.Head :: list.Tail |> List.chunkBySize chunkSize |> List.map ofList |> ofList /// For each element of the list, applies the given function. /// Concatenates all the results and returns the combined list. /// The function to transform each input element into a sublist to be concatenated. /// The input list. /// The concatenation of the transformed sublists. - let inline collect mapping (list: NonEmptyList<'T>) = list |> Seq.collect mapping |> ofSeq + let inline tryCollect mapping (list: NonEmptyList<'T>) = list |> Seq.collect mapping |> List.ofSeq /// For each element of the list, applies the given function. /// Concatenates all the results and returns the combined list. /// The function to transform each input element into a sublist to be concatenated. /// The input list. /// The concatenation of the transformed sublists. - let inline tryCollect mapping (list: NonEmptyList<'T>) = list |> Seq.collect mapping |> List.ofSeq + /// Thrown when the mapping function returns an empty list for all element. + let inline collect mapping (list: NonEmptyList<'T>) = list >>= mapping /// Returns a new list that contains the elements of each of the lists in order. /// The input list of lists. @@ -340,15 +344,16 @@ module NonEmptyList = /// The function to test the input elements. /// The input list. /// A list containing only the elements that satisfy the predicate. - let inline filter (predicate: 'T -> bool) (list: NonEmptyList<'T>): NonEmptyList<'T> = - list |> toList |> List.filter predicate |> ofList + let inline tryFilter (predicate: 'T -> bool) (list: NonEmptyList<'T>): 'T list = + list |> Seq.filter predicate |> List.ofSeq /// Returns a new collection containing only the elements of the collection for which the given predicate returns "true." /// The function to test the input elements. /// The input list. /// A list containing only the elements that satisfy the predicate. - let inline tryFilter (predicate: 'T -> bool) (list: NonEmptyList<'T>): 'T list = - list |> toList |> List.filter predicate + /// Thrown when the predicate evaluates to false for all the elements of the list. + let inline filter (predicate: 'T -> bool) (list: NonEmptyList<'T>): NonEmptyList<'T> = + list |> tryFilter predicate |> ofList /// Returns the first element for which the given function returns True. /// Raises if no such element exists. @@ -596,8 +601,8 @@ module NonEmptyList = /// A function to test each element of the list. /// The input list. /// A tuple containing the two lists. - let partition (predicate: 'T -> bool) (list: NonEmptyList<'T>) : NonEmptyList<'T> * NonEmptyList<'T> = - list |> toList |> List.partition predicate |> fun (a, b) -> (ofList a, ofList b) + let partition (predicate: 'T -> bool) (list: NonEmptyList<'T>) : 'T list * 'T list = + list |> toList |> List.partition predicate |> fun (a, b) -> (a, b) /// Applies a function to each element of the list, returning a list of the results in a random order. /// A function to generate a permutation of the list indices. @@ -639,17 +644,34 @@ module NonEmptyList = /// Removes the element at the specified index. /// The index of the element to remove. /// The input list. - /// The result list. + /// The resulting list. + let tryRemoveAt (index: int) (list: NonEmptyList<'T>) : 'T list = + list |> Seq.removeAt index |> List.ofSeq + + /// Removes the element at the specified index. + /// The index of the element to remove. + /// The input list. + /// The resulting list. + /// Thrown when removing the item results in an empty list. let removeAt (index: int) (list: NonEmptyList<'T>) : NonEmptyList<'T> = - Seq.removeAt index list |> ofSeq + tryRemoveAt index list |> ofList /// Removes multiple elements starting at the specified index. /// The index at which to start removing elements. /// The number of elements to remove. /// The input list. /// The result list. + let tryRemoveManyAt (index: int) (count: int) (list: NonEmptyList<'T>) : 'T list = + list |> Seq.removeManyAt index count |> List.ofSeq + + /// Removes multiple elements starting at the specified index. + /// The index at which to start removing elements. + /// The number of elements to remove. + /// The input list. + /// The result list. + /// Thrown when removing the items results in an empty list. let removeManyAt (index: int) (count: int) (list: NonEmptyList<'T>) : NonEmptyList<'T> = - Seq.removeManyAt index count list |> ofSeq + tryRemoveManyAt index count list |> ofList /// Creates a list that contains one repeated value. /// The number of elements. @@ -684,15 +706,31 @@ module NonEmptyList = /// The number of elements to skip. /// The input list. /// The result list. + let trySkip (count: int) (list: NonEmptyList<'T>) : 'T list = + list |> Seq.skip count |> List.ofSeq + + /// Returns a list that skips the first N elements of the list. + /// The number of elements to skip. + /// The input list. + /// The result list. + /// Thrown when resulting list is empty. let skip (count: int) (list: NonEmptyList<'T>) : NonEmptyList<'T> = - Seq.skip count list |> ofSeq + trySkip count list |> ofList /// Returns a list that skips elements while the predicate is true. /// A function to test each element of the list. /// The input list. /// The result list. + let trySkipWhile (predicate: 'T -> bool) (list: NonEmptyList<'T>) : 'T list = + list |> Seq.skipWhile predicate |> List.ofSeq + + /// Returns a list that skips elements while the predicate is true. + /// A function to test each element of the list. + /// The input list. + /// The result list. + /// Thrown when resulting list is empty. let skipWhile (predicate: 'T -> bool) (list: NonEmptyList<'T>) : NonEmptyList<'T> = - Seq.skipWhile predicate list |> ofSeq + trySkipWhile predicate list |> ofList /// Sorts the elements of the list in ascending order. /// The input list. @@ -731,8 +769,14 @@ module NonEmptyList = /// The index at which to split the list. /// The input list. /// A tuple containing the two lists. + /// Thrown when the index is 0, equal to the size of the list, or is larger than the list. let splitAt (index: int) (list: NonEmptyList<'T>) : NonEmptyList<'T> * NonEmptyList<'T> = - list |> toList |> List.splitAt index |> fun (a, b) -> (ofList a, ofList b) + if index <= 0 then + raise <| new System.InvalidOperationException("Index must be greater than 0.") + else if index >= list.Length then + raise <| new System.InvalidOperationException("Index must be less than the length of the list.") + else + list |> toList |> List.splitAt index |> fun (a, b) -> (ofList a, ofList b) /// Splits the list into the specified number of lists. /// The number of lists to create. @@ -758,22 +802,51 @@ module NonEmptyList = /// The number of elements to take. /// The input list. /// The result list. + let tryTake (count: int) (list: NonEmptyList<'T>) : 'T list = + Seq.take count list |> List.ofSeq + + /// Returns a list that contains the first N elements of the list. + /// The number of elements to take. + /// The input list. + /// The result list. + /// Thrown when the count is less than or equal to zero. let take (count: int) (list: NonEmptyList<'T>) : NonEmptyList<'T> = - Seq.take count list |> ofSeq + if count <= 0 then + raise <| new System.ArgumentException("Count must be greater than 0.") + else + tryTake count list |> ofList + + /// Returns a list that contains the elements of the list while the predicate is true. + /// A function to test each element of the list. + /// The input list. + /// The result list. + let tryTakeWhile (predicate: 'T -> bool) (list: NonEmptyList<'T>) : 'T list = + Seq.takeWhile predicate list |> List.ofSeq /// Returns a list that contains the elements of the list while the predicate is true. /// A function to test each element of the list. /// The input list. /// The result list. + /// Thrown when resulting list is empty. let takeWhile (predicate: 'T -> bool) (list: NonEmptyList<'T>) : NonEmptyList<'T> = - Seq.takeWhile predicate list |> ofSeq + tryTakeWhile predicate list |> ofList + + /// Truncates the list to the specified length. + /// The maximum number of elements to include in the list. + /// The input list. + /// The truncated list. + let tryTruncate (count: int) (list: NonEmptyList<'T>) : 'T list = + Seq.truncate count list |> List.ofSeq /// Truncates the list to the specified length. /// The maximum number of elements to include in the list. /// The input list. /// The truncated list. let truncate (count: int) (list: NonEmptyList<'T>) : NonEmptyList<'T> = - Seq.truncate count list |> ofSeq + if count <= 0 then + raise <| new System.ArgumentException("Count must be greater than 0.") + else + tryTruncate count list |> ofList /// Returns the only element of the list, or None if the list does not contain exactly one element. /// The input list. diff --git a/src/FSharpPlus/Data/NonEmptySeq.fs b/src/FSharpPlus/Data/NonEmptySeq.fs index 967445937..45c321b46 100644 --- a/src/FSharpPlus/Data/NonEmptySeq.fs +++ b/src/FSharpPlus/Data/NonEmptySeq.fs @@ -121,30 +121,31 @@ module NonEmptySeq = /// The result sequence. /// Thrown when the input sequence is null. let cast (source: _ NonEmptySeq) = Seq.cast source |> unsafeOfSeq - + /// - /// Applies a function to each element in a list and then returns a list of values v where the applied function returned Some(v). + /// Applies a function to each element in a sequence and then returns a sequence of values v where the applied function returned Some(v). /// /// The function to be applied to the list elements. /// The input sequence. - /// The resulting list comprising the values v where the chooser function returned Some(x). - let inline choose chooser (source: NonEmptySeq<'T>) = source |> Seq.choose chooser |> unsafeOfSeq - + /// The resulting sequence comprising the values v where the chooser function returned Some(x). + let inline tryChoose chooser (source: NonEmptySeq<'T>) = source |> Seq.choose chooser + /// - /// Applies a function to each element in a list and then returns a list of values v where the applied function returned Some(v). + /// Applies a function to each element in a sequence and then returns a sequence of values v where the applied function returned Some(v). /// - /// The function to be applied to the list elements. + /// The function to be applied to the sequence elements. /// The input sequence. - /// The resulting list comprising the values v where the chooser function returned Some(x). - let inline tryChoose chooser (source: NonEmptySeq<'T>) = source |> Seq.choose chooser |> List.ofSeq + /// The resulting sequence comprising the values v where the chooser function returned Some(x). + /// Thrown when the chooser function returns None for all elements. + let inline choose chooser (source: NonEmptySeq<'T>) = source |> tryChoose chooser |> unsafeOfSeq - /// Divides the input list into lists (chunks) of size at most chunkSize. - /// Returns a new list containing the generated lists (chunks) as its elements. + /// Divides the input sequence into sequences (chunks) of size at most chunkSize. + /// Returns a new sequence containing the generated sequences (chunks) as its elements. /// The maximum size of each chunk. /// The input sequence. /// The sequence divided into chunks. - let inline chunkBySize chunkSize (source: NonEmptySeq<'T>) = - source |> Seq.chunkBySize chunkSize |> Seq.map unsafeOfSeq + let inline chunkBySize chunkSize (source: NonEmptySeq<'T>): NonEmptySeq> = + source |> Seq.chunkBySize chunkSize |> Seq.map unsafeOfSeq |> unsafeOfSeq /// Applies the given function to each element of the sequence and concatenates all the /// results. @@ -671,16 +672,33 @@ module NonEmptySeq = /// The index of the element to remove. /// The input sequence. /// The result sequence. + let tryRemoveAt (index: int) (source: NonEmptySeq<'T>) : 'T seq = + Seq.removeAt index source + + /// Removes the element at the specified index. + /// The index of the element to remove. + /// The input sequence. + /// The result sequence. + /// Thrown when removing the item results in an empty sequence. let removeAt (index: int) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = - Seq.removeAt index source |> unsafeOfSeq + tryRemoveAt index source |> unsafeOfSeq /// Removes multiple elements starting at the specified index. /// The index at which to start removing elements. /// The number of elements to remove. /// The input sequence. /// The result sequence. + let tryRemoveManyAt (index: int) (count: int) (source: NonEmptySeq<'T>) : 'T seq = + Seq.removeManyAt index count source + + /// Removes multiple elements starting at the specified index. + /// The index at which to start removing elements. + /// The number of elements to remove. + /// The input sequence. + /// The result sequence. + /// Thrown when removing the items results in an empty sequence. let removeManyAt (index: int) (count: int) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = - Seq.removeManyAt index count source |> unsafeOfSeq + tryRemoveManyAt index count source |> unsafeOfSeq /// Creates a sequence that contains one repeated value. /// The number of elements. @@ -728,15 +746,31 @@ module NonEmptySeq = /// The number of elements to skip. /// The input sequence. /// The result sequence. + let trySkip (count: int) (source: NonEmptySeq<'T>) : 'T seq = + Seq.skip count source + + /// Returns a sequence that skips the first N elements of the list. + /// The number of elements to skip. + /// The input sequence. + /// The result sequence. + /// Thrown when resulting list is empty. let skip (count: int) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = - Seq.skip count source |> unsafeOfSeq + trySkip count source |> unsafeOfSeq /// Returns a sequence that skips elements while the predicate is true. /// A function to test each element of the sequence. /// The input sequence. /// The result sequence. + let trySkipWhile (predicate: 'T -> bool) (source: NonEmptySeq<'T>) : 'T seq = + Seq.skipWhile predicate source + + /// Returns a sequence that skips elements while the predicate is true. + /// A function to test each element of the sequence. + /// The input sequence. + /// The result sequence. + /// Thrown when resulting list is empty. let skipWhile (predicate: 'T -> bool) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = - Seq.skipWhile predicate source |> unsafeOfSeq + trySkipWhile predicate source |> unsafeOfSeq /// Yields a sequence ordered by keys. /// @@ -847,21 +881,44 @@ module NonEmptySeq = /// The number of elements to take. /// The input sequence. /// The result sequence. + let tryTake (count: int) (source: NonEmptySeq<'T>) : 'T seq = + Seq.take count source + + /// Returns a sequence that contains the first N elements of the sequence. + /// The number of elements to take. + /// The input sequence. + /// The result sequence. + /// Thrown when the count is less than or equal to zero. let take (count: int) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = - Seq.take count source |> unsafeOfSeq + if count <= 0 then + raise <| new System.ArgumentException("Count must be greater than 0.") + else + tryTake count source |> unsafeOfSeq + + /// Returns a sequence that contains the elements of the sequence while the predicate is true. + /// A function to test each element of the sequence. + /// The input sequence. + /// The result sequence. + let tryTakeWhile (predicate: 'T -> bool) (source: NonEmptySeq<'T>) : 'T seq = + Seq.takeWhile predicate source /// Returns a sequence that contains the elements of the sequence while the predicate is true. /// A function to test each element of the sequence. /// The input sequence. /// The result sequence. + /// Thrown when resulting sequence is empty. let takeWhile (predicate: 'T -> bool) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = - Seq.takeWhile predicate source |> unsafeOfSeq + tryTakeWhile predicate source |> unsafeOfSeq /// Truncates the sequence to the specified length. /// The maximum number of elements to include in the sequence. /// The input sequence. /// The truncated sequence. + /// Thrown when the count is less than or equal to zero. let truncate (count: int) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = + if count <= 0 then + raise <| new System.ArgumentException("Count must be greater than 0.") + else Seq.truncate count source |> unsafeOfSeq /// Returns the only element of the sequence, or None if the sequence does not contain exactly one element.