FSharpCoreMissingParts is a collection of various useful functions intended to fill missing parts of the F# Core library.
You can install FSharpCoreMissingParts via NuGet:
Install-Package FSharpCoreMissingPartsOr via .NET CLI:
dotnet add package FSharpCoreMissingPartsTo use FSharpCoreMissingParts in your F# project:
open FSharpCoreMissingPartsIf you want to use flexible numeric casting:
open FSharpCoreMissingParts.CastingPerforms a binary search within the specified array. The array must be sorted, otherwise the result can be wrong.
> [|1 .. 100|] |> Array.tryBinarySearch 42;;
val it : int option = Some 41Performs a binary search within the specified array using an external compare function. The array must be sorted, otherwise the result can be wrong.
> let reverseCompare a b = compare b a
[|100 .. -1 .. 1|] |> Array.tryBinarySearchWith reverseCompare 42;;
val it : int option = Some 58Create a 2D array from a 1D array by specifying dimensions (rows and columns).
> let nrows, ncolumns = 3, 2;;
val nrows: int = 3
val ncolumns: int = 2
> let arr2d = [|1 .. 6|] |> Array2D.ofArray nrows ncolumns;;
val arr2d : int [,] = [[1; 2]
[3; 4]
[5; 6]]Flattens a 2D array back into a 1D array.
> arr2d |> Array2D.toArray;;
val it : int [] = [|1; 2; 3; 4; 5; 6|]A type-safe cast operator that performs flexible numeric conversions.
let inline sqrtn n = (n |> float |> sqrt) ^> n
> sqrtn 25;;
val it : int = 5
> sqrtn 25I;;
val it : bigint = 5
> sqrtn 25.;;
val it : double = 5.0Creates an immutable circular list where the last element points back to the first.
> let head = CircularList.ofList [1; 2];;
val head : CircularListNode<int>
> head |> CircularList.value;;
val it : int = 1
> head |> CircularList.next |> CircularList.value;;
val it : int = 2
> head |> CircularList.next |> CircularList.next |> CircularList.value;;
val it : int = 1Returns the actual data stored in the current node.
Returns the next node in the list. Since the list is circular, calling next on the last element will seamlessly point back to the first element, allowing for infinite traversal without encountering null or None.
A wrap-around version of List.pairwise that pairs the last element with the first.
> [1] |> List.pairwiseWrapped;;
val it : (int * int) list = [(1, 1)]
> [1 .. 3] |> List.pairwiseWrapped;;
val it : (int * int) list = [(1, 2); (2, 3); (3, 1)]Applies a mapper function to the Cartesian product of two lists. Equivalent to allPairs + map.
> List.crossMap (+) [1; 2] [10; 20];;
val it: int list = [11; 21; 12; 22]A functional style wrapper for ReadOnlyMemory<'T>, allowing zero-allocation slicing and iteration.
Wraps an entire array into a ReadOnlyMemory<'T>. This provides a view of the array without copying its elements.
Creates a ReadOnlyMemory<'T> from a specific range of an array. It takes a start index and a length, allowing you to work with a sub-section of the array efficiently.
Converts a string into a ReadOnlyMemory<char>. This is useful for performing high-performance string operations without additional allocations.
Creates a ReadOnlyMemory<char> from a sub-string based on the start index and length. Unlike String.Substring, this operation does not allocate a new string on the heap.
Yields a sequence of overlapping slices (windows) of the specified size.
> "Hello" |> Mem.ofString |> Mem.windowed 3 |> Seq.map string
val it : seq<string> = seq ["Hel"; "ell"; "llo"]Returns true if all elements satisfy the given predicate.
> let mem = Mem.ofArray [|1; 2; 3; 4; 5|];;
val mem : ReadOnlyMemory<int> = 1 2 3 4 5
> Mem.forall (fun x -> x > 0) mem;;
val it : bool = trueReturns true if all elements satisfy the given predicate. The predicate takes two arguments, one from each memory block.
> let mem = Mem.ofArray [|1; 2; 3; 4; 5|];;
val mem : ReadOnlyMemory<int> = 1 2 3 4 5
> let mem2 = Mem.ofArray [|5; 4; 3; 2; 1|];;
val mem2 : ReadOnlyMemory<int> = 5 4 3 2 1
> Mem.forall2 (fun x y -> x + y = 6) mem mem2;;
val it : bool = trueProvides "human-friendly" sorting that handles numbers within strings logically.
> ["z10"; "z"; "z1"; "z012"; "zz"; "z21"; "z2"] |> NaturalSort.sort;;
val it : string list = ["z"; "z1"; "z2"; "z10"; "z012"; "z21"; "zz"]F# implementation of C# nullable type.
Generates an infinite sequence by repeatedly applying a function to an initial value. Each element is the result of applying the function to the previous element.
> Seq.iterate (fun x -> x * 2) 1 |> Seq.take 5 |> Seq.toList;;
val it : int list = [1; 2; 4; 8; 16]Similar to Seq.fold, but allows early termination. The folding process continues as long as the folder function returns Some. If it returns None, the sequence processing stops immediately and returns the last state.
> let folder state x =
if x < 5
then Some (state + x)
else None;;
val folder : state:int -> x:int -> int option
> [1 .. 10] |> Seq.foldSome folder 0;;
val it : int = 10Checks if a sequence is sorted according to the specified SortOrder, which is one of Ascending, Descending, StrictAscending, or StrictDescending.
> [1; 2; 2; 3] |> Seq.isOrdered Ascending;;
val it : bool = true
> [1; 2; 2; 3] |> Seq.isOrdered StrictAscending;;
val it : bool = false
> [3; 3; 2; 1] |> Seq.isOrdered Descending;;
val it : bool = true
> [3; 3; 2; 1] |> Seq.isOrdered StrictDescending;;
val it : bool = falseCreates a string from the specified char sequence.
> ['a' .. 'f'] |> String.ofSeq;;
val it : string = "abcdef"Shortens a string to the specified length. The last character is replaced with an ellipsis (U+2026).
> "abcde" |> String.ellipsize 3;;
val it : string = "ab…"Generates all suffixes of the string, from longest to shortest.
> "bjy" |> String.suffixes;;
val it : string seq = seq ["bjy"; "jy"; "y"]