Extensions are what you probably expect: helper functions for existing types.
They are defined as modules with the same name as the types they operate on
under the FSharpPlus namespace, so can be accessed via:
open FSharpPlus
Some functions are common across foldable types such as intercalate
on
List, Array and Seq, and others are common across wrapping containers,
such as map
, bind
and apply
on List, Array, and Seq, but also Option and Result.
The singleton
function is already defined for Seq, Array and List, but F#+ adds it for Enumerator:
- Enumerator.singleton - construct a container with the given value inside it
To construct MonadError instances (Result or Choice) you can use result/throw:
- Result.result / Choice.result - construct with the given value (as Ok or Choice1Of2)
- Result.throw / Choice.throw - construct an error from the given value (as Error or Choice2of2)
It's also possible to construct by wrapping exception producing functions:
- Option.protect - returns None on exception
- Result.protect - returns Error with exception value on exception
- Choice.protect - returns Choice2Of2 with exception value on exception
// throws "ArgumentException: The input sequence was empty."
let expectedSingleItem1 : int = List.exactlyOne []
// returns a Result.Error holding the exception as its value:
let expectedSingleItem2 : Result<int,exn> = Result.protect List.exactlyOne []
// ...or like typical try prefixed functions, treat exception as None
let expectedSingleItem3 : Option<int> = Option.protect List.exactlyOne []
// which might look like this:
let inline tryExactlyOne xs = Option.protect List.exactlyOne xs
Some extensions on Result are designed to behave like Option:
- Result.get - unwraps the value when it is an 'ok, otherwise throws an exception
- Result.defaultValue - return the 'ok value if present, otherwise the default value
-
Result.defaultWith - return the 'ok value if present, otherwise apply the given function
to the 'error value
To deconstruct MonadError instances (Result or Choice) use:
- Result.either - unwraps the result by applying the given
ok
or err
function as appropriate
- Choice.either - unwraps the choice by applying the given
choice1
or choice2
function as appropriate
Note that there is also the generic either
operator function that works
exactly the same as Result.either
.
Also, see the generic function option
that
unwraps an Option in a similar way to either
.
Foldables are the class of data structures that can be folded to a summary value.
Most collections, or specifically 'foldable' instances implement these:
- intersperse - takes an element and `intersperses' that element between the elements
let a = ["Bob"; "Jane"] |> List.intersperse "and"
// vat a : string list = ["Bob"; "and"; "Jane"]
let b = "WooHoo" |> String.intersperse '-'
// val b : string = "W-o-o-H-o-o"
- intercalate - insert a list of elements between each element and flattens
let c = [[1;2]; [3;4]] |> List.intercalate [-1;-2];;
// val c : int list = [1; 2; -1; -2; 3; 4]
let d = ["Woo"; "Hoo"] |> String.intercalate "--o.o--";;
// val d : string = "Woo--o.o--Hoo"
- zip/unzip - tuple together values inside two containers, or untuble tupled values
Types that implement these will (typically) have these functions defined:
- map - apply a mapping function to the value inside a container
- bind - take a contained value, and apply a function that produces another contained value
- apply - like map but where the mapping function is also inside a container
These can also be invoked from the generic functions without module prefix as per
generic functions & operators.
Flatten can be used when a container has another container inside it:
- Choice.flatten
- Result.flatten
- Option.flatten (already defined in FSharp Core)
Note that on traversable types like List, Array and Seq, FSharp Core uses the
more common concat
for flatten and so this naming is continued for Enumerable:
Partitioning can be done by applying a separating function that produces a Choice:
- Array.partitionMap
- List.partitionMap
let isEven x = (x % 2) = 0
let chooseEven x = if isEven x then Choice1Of2 x else Choice2Of2 x
let e = [1; 2; 3; 4] |> List.partitionMap chooseEven
// val e : int list * int list = ([2; 4], [1; 3])
F#+ adds functions to convert between Result, Choice and Option types.
These should be self explanatory, but be aware that sometimes they are 'lossy'
usually when converting to Option:
// Convert a Result
to an Option
- effectively throws away error value
// when present, by replacing with None
request |> validateRequest |> Option.ofResult
|
Going the other way is similar, but a value needs to be filled in for None:
let xs = ["some value"]
let firstElementOption = xs |> List.tryHead
// Convert an `Option` to a `Result` will use unit as the Error:
firstElementOption |> Option.toResult
// ...but you can specify an error value with Option.toResultWith:
firstElementOption |> Option.toResultWith "No Element"
Converting between Choice
and Result
is often useful:
let asyncChoice = anAsyncValue |> Async.Catch |> Async.map Result.ofChoice
|
-
String
- intercalate, intersperse,
- split, replace
- isSubString, startsWith, endsWith, contains
- toUpper, toLower
- trimWhiteSpaces
- normalize
- removeDiacritics
- padLeft, padLeftWith, padRight, padRightWith
- trim, trimStart, trimEnd
- item, tryItem
- rev
- take, skip takeWhile, skipWhile
- truncate, drop
- findIndex, tryFindIndex
- findSliceIndex, tryFindSliceIndex
- findLastSliceIndex, tryFindLastSliceIndex
- toArray, ofArray, toList, ofList, toSeq, ofSeq, toCodePoints, ofCodePoints
- getBytes
-
Array
- intercalate, intersperse,
- split, replace,
- findSliceIndex, trySliceIndex,
- findLastSliceIndex, tryLastSliceIndex,
- partitionMap
-
IList
-
List
- singleton,
- cons,
- apply,
- tails, take, skip, drop,
- intercalate, intersperse,
- split, replace,
- toIReadOnlyList,
- findSliceIndex, tryFindSliceIndex,
- findLastSliceIndex, tryLastSliceIndex,
- partitionMap
- setAt, removeAt
-
Enumerator
-
EmptyEnumerator
- Empty - create an empty enumerator
-
ConcatEnumerator
-
MapEnumerators
- map, mapi, map2, mapi2, map3
- singleton
- tryItem, nth
- choose
- filter
- unfold
- upto
- zip, zip3
-
Seq
- bind, apply, foldback
- chunkBy
- intersperse, intercalate,
- split, replace
- drop
- replicate
- toIReadOnlyList
- findSliceIndex, tryFindSliceIndex
- findLastSliceIndex, tryLastSliceIndex,
-
IReadOnlyCollection
- ofArray, ofList, ofSeq
- map
-
IReadOnlyList
- ofArray, toArray
- trySetItem, tryItem
-
Map
- keys, values
- mapValues, mapValues2
- zip, unzip
- unionWith, union, intersectWith, intersect
-
Dict
- toIReadOnlyDictionary
- tryGetValue
- containsKey
- keys, values
- map, map2
- zip, unzip
- unionWith, union, intersectWith, intersect
-
IReadOnlyDictionary
- add,
- tryGetValue, containsKey,
- keys, values,
- map, map2,
- zip, unzip,
- unionWith, union, intersectWith, intersect
-
Task
- map, map2, map3
- apply
- zip
- join
- ignore
-
ValueTask
- map, map2, map3
- apply
- zip
- join
- ignore
-
Async
- map, map2
- zip
- join
- apply
- raise
-
Option
- apply,
- unzip, zip,
- toResult, toResultWith, ofResult,
- protect
-
Choice
- result, throw - construct a Choice
- bind, apply, flatten,
- map,
- catch, - deprecated
- bindChoice2Of2,
- either,
- protect
-
Result
- result, throw - construct a Result
- apply, (map, bind already defined)
- flatten,
- bindError,
- either,
- protect,
- get,
- defaultValue, defaultWith,
- toChoice, ofChoice,
- partition
These are usable from C#
-
Extension Methods
- IEnumerable<'T'>.GetSlice
- List<'T>.GetSlice
- Task<'T>.WhenAll
- Async.Sequence - of seq, list or array
- Option.Sequence - of seq
namespace FSharpPlus
val expectedSingleItem1: int
Multiple items
val int: value: 'T -> int (requires member op_Explicit)
--------------------
type int = int32
--------------------
type int<'Measure> =
int
Multiple items
module List
from FSharpPlus
<summary>
Additional operations on List
</summary>
--------------------
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| op_Nil
| op_ColonColon of Head: 'T * Tail: 'T list
interface IReadOnlyList<'T>
interface IReadOnlyCollection<'T>
interface IEnumerable
interface IEnumerable<'T>
member GetReverseIndex: rank: int * offset: int -> int
member GetSlice: startIndex: int option * endIndex: int option -> 'T list
static member Cons: head: 'T * tail: 'T list -> 'T list
member Head: 'T
member IsEmpty: bool
member Item: index: int -> 'T with get
...
val exactlyOne: list: 'T list -> 'T
val expectedSingleItem2: Result<int,exn>
Multiple items
module Result
from FSharpPlus
<summary>
Additional operations on Result<'T,'Error>
</summary>
--------------------
module Result
from Microsoft.FSharp.Core
--------------------
[<Struct>]
type Result<'T,'TError> =
| Ok of ResultValue: 'T
| Error of ErrorValue: 'TError
type exn = System.Exception
val protect: f: ('T -> 'U) -> x: 'T -> Result<'U,exn>
<summary>
Creates a safe version of the supplied function, which returns a Result<'U,exn> instead of throwing exceptions.
</summary>
val expectedSingleItem3: Option<int>
Multiple items
module Option
from FSharpPlus
<summary>
Additional operations on Option
</summary>
--------------------
module Option
from Microsoft.FSharp.Core
val protect: f: ('T -> 'U) -> x: 'T -> 'U option
<summary>
Creates a safe version of the supplied function, which returns an option<'U> instead of throwing exceptions.
</summary>
val tryExactlyOne: xs: 'a list -> 'a option
val xs: 'a list
val a: string list
val intersperse: separator: 'T -> source: 'T list -> 'T list
<summary>
Inserts a separator element between each element in the source list.
</summary>
val b: string
Multiple items
module String
from FSharpPlus
<summary>
Additional operations on String
</summary>
--------------------
module String
from Microsoft.FSharp.Core
val intersperse: element: char -> source: string -> string
<summary>
Inserts a separator char between each char in the source string.
</summary>
val c: int list
val intercalate: separator: 'T list -> source: 'T list seq -> 'T list
<summary>
Concatenates all elements, using the specified separator between each element.
</summary>
val d: string
val intercalate: separator: string -> source: string seq -> string
<summary>
Concatenates all elements, using the specified separator between each element.
</summary>
val isEven: x: int -> bool
val x: int
val chooseEven: x: int -> Choice<int,int>
union case Choice.Choice1Of2: 'T1 -> Choice<'T1,'T2>
union case Choice.Choice2Of2: 'T2 -> Choice<'T1,'T2>
val e: int list * int list
val partitionMap: mapping: ('T -> Choice<'T1,'T2>) -> source: 'T list -> 'T1 list * 'T2 list
<summary>
Creates two lists by applying the mapping function to each element in the list
and classifying the transformed values depending on whether they were wrapped with Choice1Of2 or Choice2Of2.
</summary>
<returns>
A tuple with both resulting lists.
</returns>
val xs: string list
val firstElementOption: string option
val tryHead: list: 'T list -> 'T option
val toResult: source: 'T option -> Result<'T,unit>
<summary>Converts an option to a Result.</summary>
<param name="source">The option value.</param>
<returns>The resulting Result value.</returns>
val toResultWith: errorValue: 'Error -> source: 'T option -> Result<'T,'Error>
<summary>Converts an option to a Result.</summary>
<param name="errorValue">The error value to be used in case of None.</param>
<param name="source">The option value.</param>
<returns>The resulting Result value.</returns>