FSharpPlus


Extensions

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.

Construction:

The singleton function is already defined for Seq, Array and List, but F#+ adds it for Enumerator:

To construct MonadError instances (Result or Choice) you can use result/throw:

It's also possible to construct by wrapping exception producing functions:

// 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

Deconstruction (unwrapping):

Some extensions on Result are designed to behave like Option:

To deconstruct MonadError instances (Result or Choice) use:

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.

On Foldables

Foldables are the class of data structures that can be folded to a summary value. Most collections, or specifically 'foldable' instances implement these:

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"
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"

On Monad/Functor/Applicatives

Types that implement these will (typically) have these functions defined:

These can also be invoked from the generic functions without module prefix as per generic functions & operators.

Flatten:

Flatten can be used when a container has another container inside it:

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:

Partitioning can be done by applying a separating function that produces a Choice:

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])

Conversion functions:

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

The String type:

Collections / Traversable types:

Async, Task and ValueTask:

Option, Choice and Result types:

Extensions Methods (on existing types):

These are usable from C#

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&lt;'T,'Error&gt; </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&lt;'U,exn&gt; 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&lt;'U&gt; 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: seq<'T list> -> 'T list
<summary> Concatenates all elements, using the specified separator between each element. </summary>
val d: string
val intercalate: separator: string -> source: seq<string> -> 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>