Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add List.chooseV, Seq.tryPickV, etc. for ValueOption #6781

Closed
wants to merge 12 commits into from
Closed
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
81 changes: 81 additions & 0 deletions src/fsharp/FSharp.Core/array.fs
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,18 @@ namespace Microsoft.FSharp.Collections
| None -> loop(i+1)
| Some res -> res
loop 0

[<CompiledName("PickV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
let pickV chooser (array: _[]) =
checkNonNull "array" array
let rec loop i =
if i >= array.Length then
indexNotFound()
else
match chooser array.[i] with
| ValueNone -> loop(i+1)
| ValueSome res -> res
loop 0

[<CompiledName("TryPick")>]
let tryPick chooser (array: _[]) =
Expand All @@ -474,6 +486,16 @@ namespace Microsoft.FSharp.Collections
| None -> loop(i+1)
| res -> res
loop 0

[<CompiledName("TryPickV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
let tryPickV chooser (array: _[]) =
checkNonNull "array" array
let rec loop i =
if i >= array.Length then ValueNone else
match chooser array.[i] with
| ValueNone -> loop(i+1)
| res -> res
loop 0

[<CompiledName("Choose")>]
let choose (chooser: 'T -> 'U Option) (array: 'T[]) =
Expand Down Expand Up @@ -521,6 +543,53 @@ namespace Microsoft.FSharp.Collections
Microsoft.FSharp.Primitives.Basics.Array.subUnchecked 0 count chunk1
else
empty

[<CompiledName("ChooseV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
let chooseV (chooser: 'T -> 'U ValueOption) (array: 'T[]) =
checkNonNull "array" array

let mutable i = 0
let mutable first = Unchecked.defaultof<'U>
let mutable found = false
while i < array.Length && not found do
let element = array.[i]
match chooser element with
| ValueNone -> i <- i + 1
| ValueSome b -> first <- b; found <- true

if i <> array.Length then

let chunk1: 'U[] = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked ((array.Length >>> 2) + 1)
chunk1.[0] <- first
let mutable count = 1
i <- i + 1
while count < chunk1.Length && i < array.Length do
let element = array.[i]
match chooser element with
| ValueNone -> ()
| ValueSome b -> chunk1.[count] <- b
count <- count + 1
i <- i + 1

if i < array.Length then
let chunk2: 'U[] = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked (array.Length-i)
count <- 0
while i < array.Length do
let element = array.[i]
match chooser element with
| ValueNone -> ()
| ValueSome b -> chunk2.[count] <- b
count <- count + 1
i <- i + 1

let res: 'U[] = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked (chunk1.Length + count)
Array.Copy(chunk1, res, chunk1.Length)
Array.Copy(chunk2, 0, res, chunk1.Length, count)
res
else
Microsoft.FSharp.Primitives.Basics.Array.subUnchecked 0 count chunk1
else
empty

// The filter module is a space and performance for Array.filter based optimization that uses
// a bitarray to store the results of the filtering of every element of the array. This means
Expand Down Expand Up @@ -864,6 +933,18 @@ namespace Microsoft.FSharp.Collections
loop s'
loop state
res.ToArray()

[<CompiledName("UnfoldV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
let unfoldV<'T, 'State> (generator: 'State -> ('T*'State) voption) (state: 'State) =
let res = ResizeArray<_>()
let rec loop state =
match generator state with
| ValueNone -> ()
| ValueSome (x, s') ->
res.Add(x)
loop s'
loop state
res.ToArray()

[<CompiledName("Unzip")>]
let unzip (array: _[]) =
Expand Down
41 changes: 41 additions & 0 deletions src/fsharp/FSharp.Core/array.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,16 @@ namespace Microsoft.FSharp.Collections
/// <exception cref="System.ArgumentNullException">Thrown when the input array is null.</exception>
[<CompiledName("TryPick")>]
val tryPick: chooser:('T -> 'U option) -> array:'T[] -> 'U option

/// <summary>Applies the given function to successive elements, returning the first
/// result where function returns <c>ValueSome(x)</c> for some <c>x</c>. If the function
/// never returns <c>ValueSome(x)</c> then <c>ValueNone</c> is returned.</summary>
/// <param name="chooser">The function to transform the array elements into options.</param>
/// <param name="array">The input array.</param>
/// <returns>The first transformed element that is <c>ValueSome(x)</c>.</returns>
/// <exception cref="System.ArgumentNullException">Thrown when the input array is null.</exception>
[<CompiledName("TryPickV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
val tryPickV: chooser:('T -> 'U voption) -> array:'T[] -> 'U voption

/// <summary>Fills a range of elements of the array with the given value.</summary>
/// <param name="target">The target array.</param>
Expand All @@ -172,6 +182,18 @@ namespace Microsoft.FSharp.Collections
/// <returns>The first result.</returns>
[<CompiledName("Pick")>]
val pick: chooser:('T -> 'U option) -> array:'T[] -> 'U

/// <summary>Applies the given function to successive elements, returning the first
/// result where function returns <c>ValueSome(x)</c> for some <c>x</c>. If the function
/// never returns <c>ValueSome(x)</c> then <c>KeyNotFoundException</c> is raised.</summary>
/// <param name="chooser">The function to generate options from the elements.</param>
/// <param name="array">The input array.</param>
/// <exception cref="System.ArgumentNullException">Thrown when the input array is null.</exception>
/// <exception cref="System.Collections.Generic.KeyNotFoundException">Thrown if every result from
/// <c>chooser</c> is <c>ValueNone</c>.</exception>
/// <returns>The first result.</returns>
[<CompiledName("PickV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
val pickV: chooser:('T -> 'U voption) -> array:'T[] -> 'U

/// <summary>Applies the given function to each element of the array. Returns
/// the array comprised of the results "x" for each element where
Expand All @@ -182,6 +204,16 @@ namespace Microsoft.FSharp.Collections
/// <exception cref="System.ArgumentNullException">Thrown when the input array is null.</exception>
[<CompiledName("Choose")>]
val choose: chooser:('T -> 'U option) -> array:'T[] -> 'U[]

/// <summary>Applies the given function to each element of the array. Returns
/// the array comprised of the results "x" for each element where
/// the function returns ValueSome(x)</summary>
/// <param name="chooser">The function to generate options from the elements.</param>
/// <param name="array">The input array.</param>
/// <returns>The array of results.</returns>
/// <exception cref="System.ArgumentNullException">Thrown when the input array is null.</exception>
[<CompiledName("ChooseV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
val chooseV: chooser:('T -> 'U voption) -> array:'T[] -> 'U[]

/// <summary>Divides the input array into chunks of size at most <c>chunkSize</c>.</summary>
/// <param name="chunkSize">The maximum size of each chunk.</param>
Expand Down Expand Up @@ -1064,6 +1096,15 @@ namespace Microsoft.FSharp.Collections
/// <returns>The result array.</returns>
[<CompiledName("Unfold")>]
val unfold<'T,'State> : generator:('State -> ('T * 'State) option) -> state:'State -> 'T[]

/// <summary>Returns an array that contains the elements generated by the given computation.
/// The given initial <c>state</c> argument is passed to the element generator.</summary>
/// <param name="generator">A function that takes in the current state and returns an option tuple of the next
/// element of the array and the next state value.</param>
/// <param name="state">The initial state value.</param>
/// <returns>The result array.</returns>
[<CompiledName("UnfoldV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
val unfoldV<'T,'State> : generator:('State -> ('T * 'State) voption) -> state:'State -> 'T[]

/// <summary>Splits an array of pairs into two arrays.</summary>
/// <param name="array">The input array.</param>
Expand Down
6 changes: 6 additions & 0 deletions src/fsharp/FSharp.Core/eventmodule.fs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ namespace Microsoft.FSharp.Control
let ev = new Event<_>()
sourceEvent.Add(fun x -> match chooser x with None -> () | Some r -> ev.Trigger r)
ev.Publish

[<CompiledName("ChooseV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
let chooseV chooser (sourceEvent: IEvent<'Delegate,'T>) =
let ev = new Event<_>()
sourceEvent.Add(fun x -> match chooser x with ValueNone -> () | ValueSome r -> ev.Trigger r)
ev.Publish

[<CompiledName("Scan")>]
let scan collector state (sourceEvent: IEvent<'Delegate,'T>) =
Expand Down
8 changes: 8 additions & 0 deletions src/fsharp/FSharp.Core/eventmodule.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ namespace Microsoft.FSharp.Control
/// <returns>An event that fires only when the chooser returns Some.</returns>
[<CompiledName("Choose")>]
val choose: chooser:('T -> 'U option) -> sourceEvent:IEvent<'Del,'T> -> IEvent<'U>

/// <summary>Returns a new event which fires on a selection of messages from the original event.
/// The selection function takes an original message to an optional new message.</summary>
/// <param name="chooser">The function to select and transform event values to pass on.</param>
/// <param name="sourceEvent">The input event.</param>
/// <returns>An event that fires only when the chooser returns ValueSome.</returns>
[<CompiledName("ChooseV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
val chooseV: chooser:('T -> 'U voption) -> sourceEvent:IEvent<'Del,'T> -> IEvent<'U>

[<CompiledName("Scan")>]
/// <summary>Returns a new event consisting of the results of applying the given accumulating function
Expand Down
24 changes: 24 additions & 0 deletions src/fsharp/FSharp.Core/list.fs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ namespace Microsoft.FSharp.Collections

[<CompiledName("Choose")>]
let choose chooser list = Microsoft.FSharp.Primitives.Basics.List.choose chooser list

[<CompiledName("ChooseV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
let chooseV chooser list = Microsoft.FSharp.Primitives.Basics.List.chooseV chooser list

[<CompiledName("SplitAt")>]
let splitAt index (list:'T list) = Microsoft.FSharp.Primitives.Basics.List.splitAt index list
Expand Down Expand Up @@ -410,6 +413,15 @@ namespace Microsoft.FSharp.Collections
match chooser h with
| None -> tryPick chooser t
| r -> r

[<CompiledName("TryPickV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
let rec tryPickV chooser list =
match list with
| [] -> ValueNone
| h :: t ->
match chooser h with
| ValueNone -> tryPickV chooser t
| r -> r

[<CompiledName("Pick")>]
let rec pick chooser list =
Expand All @@ -419,6 +431,15 @@ namespace Microsoft.FSharp.Collections
match chooser h with
| None -> pick chooser t
| Some r -> r

[<CompiledName("PickV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
let rec pickV chooser list =
match list with
| [] -> indexNotFound()
| h :: t ->
match chooser h with
| ValueNone -> pickV chooser t
| ValueSome r -> r

[<CompiledName("Filter")>]
let filter predicate list = Microsoft.FSharp.Primitives.Basics.List.filter predicate list
Expand Down Expand Up @@ -700,3 +721,6 @@ namespace Microsoft.FSharp.Collections

[<CompiledName("Unfold")>]
let unfold<'T, 'State> (generator:'State -> ('T*'State) option) (state:'State) = Microsoft.FSharp.Primitives.Basics.List.unfold generator state

[<CompiledName("UnfoldV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
let unfoldV<'T, 'State> (generator:'State -> ('T*'State) voption) (state:'State) = Microsoft.FSharp.Primitives.Basics.List.unfoldV generator state
37 changes: 37 additions & 0 deletions src/fsharp/FSharp.Core/list.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ namespace Microsoft.FSharp.Collections
/// <returns>The list comprising the values selected from the chooser function.</returns>
[<CompiledName("Choose")>]
val choose: chooser:('T -> 'U option) -> list:'T list -> 'U list

/// <summary>Applies the given function to each element of the list. Returns
/// the list comprised of the results <c>x</c> for each element where
/// the function returns ValueSome(x)</summary>
/// <param name="chooser">The function to generate options from the elements.</param>
/// <param name="list">The input list.</param>
/// <returns>The list comprising the values selected from the chooser function.</returns>
[<CompiledName("ChooseV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
val chooseV: chooser:('T -> 'U voption) -> list:'T list -> 'U list

/// <summary>Divides the input list into chunks of size at most <c>chunkSize</c>.</summary>
/// <param name="chunkSize">The maximum size of each chunk.</param>
Expand Down Expand Up @@ -575,6 +584,16 @@ namespace Microsoft.FSharp.Collections
/// <returns>The first resulting value.</returns>
[<CompiledName("Pick")>]
val pick: chooser:('T -> 'U option) -> list:'T list -> 'U

/// <summary>Applies the given function to successive elements, returning the first
/// result where function returns <c>ValueSome(x)</c> for some x. If no such
/// element exists then raise <c>System.Collections.Generic.KeyNotFoundException</c></summary>
/// <param name="chooser">The function to generate options from the elements.</param>
/// <param name="list">The input list.</param>
/// <exception cref="System.Collections.Generic.KeyNotFoundException">Thrown when the list is empty.</exception>
/// <returns>The first resulting value.</returns>
[<CompiledName("PickV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
val pickV: chooser:('T -> 'U voption) -> list:'T list -> 'U

/// <summary>Returns a list with all elements permuted according to the
/// specified permutation.</summary>
Expand Down Expand Up @@ -813,6 +832,15 @@ namespace Microsoft.FSharp.Collections
/// <returns>The first resulting value or None.</returns>
[<CompiledName("TryPick")>]
val tryPick: chooser:('T -> 'U option) -> list:'T list -> 'U option

/// <summary>Applies the given function to successive elements, returning <c>ValueSome(x)</c> the first
/// result where function returns <c>ValueSome(x)</c> for some x. If no such element
/// exists then return <c>ValueNone</c>.</summary>
/// <param name="chooser">The function to generate options from the elements.</param>
/// <param name="list">The input list.</param>
/// <returns>The first resulting value or ValueNone.</returns>
[<CompiledName("TryPickV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
val tryPickV: chooser:('T -> 'U voption) -> list:'T list -> 'U voption

/// <summary>Returns the first element for which the given function returns True.
/// Return None if no such element exists.</summary>
Expand Down Expand Up @@ -868,6 +896,15 @@ namespace Microsoft.FSharp.Collections
/// <returns>The result list.</returns>
[<CompiledName("Unfold")>]
val unfold<'T,'State> : generator:('State -> ('T * 'State) option) -> state:'State -> 'T list

/// <summary>Returns a list that contains the elements generated by the given computation.
/// The given initial <c>state</c> argument is passed to the element generator.</summary>
/// <param name="generator">A function that takes in the current state and returns an option tuple of the next
/// element of the list and the next state value.</param>
/// <param name="state">The initial state value.</param>
/// <returns>The result list.</returns>
[<CompiledName("UnfoldV");Experimental(ExperimentalAttributeMessages.RequiresPreview)>]
val unfoldV<'T,'State> : generator:('State -> ('T * 'State) voption) -> state:'State -> 'T list

/// <summary>Splits a list of pairs into two lists.</summary>
/// <param name="list">The input list.</param>
Expand Down
Loading