This library allows to use some common computation expressions without writing any boiler plate code.
For applicatives there is single computation expression: applicative { .. }
. Additionally applicative2 { .. }
and applicative3 { .. }
exists for composed (aka layered) applicatives.
For monadic code there is a single computation expression: monad { .. }
but it comes in 4 flavours:

Delayed or strict
Delayed computations require that the type implements a TryWith, TryFinally and optionally a Delay method.
F# comes with async and seq computation expressions, both are delayed.

It can have embedded sideeffects or act as a monadplus
A monadplus can return (or yield) many times, so for example all expressions in a loop can be returned, whereas in the other model those expressions are of type unit, since a side effect is expected.
Async workflows is an example of a sideeffect computation expression and seq expressions are an example of monadplus.
Side effect workflows don't have any additional requirement over the type (apart from the monad operations), but monadplus requires the additional get_Empty and (<>) methods.
The generic computation expression monad
is a sideeffect one, but it can be turned into a monadplus by accessing the .plus
property.
Note that monad.fx
is an alias for monad
: fx is used as an abbreviation for sideeffects.
These computations are lazy by default, but they can be made strict by adding .strict
or using a '
, ie monad.plus'
.
In other words:
monad.fx
or simply monad
: Lazy monadic builder. Use when you want to use sideeffects instead of the additive behavior of monad plus.
monad.fx.strict
(or monad.fx'
or simply monad.strict
or monad'
) is the strict version of monad
.
monad.plus
: Lazy additive monadic builder. Use when you expect one or more results.
monad.plus'
is the strict version of monad.plus
Note that a type is either lazy or strict, but it could act as fx or plus at the same time (see below some examples). This means that we need to pay attention when using a CE over a type, if the type is lazy but with use a strict monad, we'll get strict semantics which probably would make no sense, but if we do the opposite we might run into runtime errors, fortunately a compiletime warning (or error) will prevent us.
A simple way to find out if a type is strict or lazy is to execute this in fsi: let _ : MyType<'t> = monad { printfn "I'm strict" }
For layered monads (monad transformers) the general rule is: the monad is strict unless at least one of its constituent types is lazy, in that case the whole monad becomes lazy.
let _ : OptionT<list<unit option>> = monad { printfn "I'm strict" }
// will print I'm strict, because OptionT and list are strict
let _ : OptionT<seq<unit option>> = monad { printfn "I'm strict" }
// won't print anything, because seq is lazy
You may run this script stepbystep.
open FSharpPlus
let lazyValue = monad {
let! a = lazy (printfn "I'm lazy"; 2)
let! b = lazy (printfn "I'm lazy too"; 10)
return a + b}
// val lazyValue : System.Lazy<int> = Value is not created.
let res12 = lazyValue.Value
let maybeWithSideFx = monad' {
let! a = Some 3
let b = ref 0
while !b < 10 do
let! n = Some ()
incr b
if a = 3 then printfn "got 3"
else printfn "got something else (will never print this)"
return a }
// val maybeWithSideFx : int option = Some 3
let lst = [None; None; Some 2; Some 4; Some 10; None]
let maybeManyTimes = monad.plus' {
let defaultValue = 42
let mutable i = 0
return! None
while i < 5 do
printfn "looping %i" i
i < i + 1
return! lst.[i]
printfn "halfway"
return! None
printfn "near the end"
return defaultValue }
// val maybeManyTimes : int option = Some 2
let (asnNumber: Async<_>) = monad.fx {
let mutable m = ResizeArray ()
try
for i = 1 to 10 do
m.Add i
return m.[1]
with e >
return 3 }
let (lstNumber: list<_>) = monad.plus' {
try
for i = 1 to 10 do
return i
with e >
return 3 }
(*
For more information about computation expressions you can read the paper : The F# Computation Expression Zoo
http://tomasp.net/academic/papers/computationzoo/computationzoo.pdf
*)
namespace FSharpPlus
namespace FSharpPlus.Data
Multiple items
union case OptionT.OptionT: 'monad<option<'t>> > OptionT<'monad<option<'t>>>

module OptionT
from FSharpPlus.Data
<summary>
Basic operations on OptionT
</summary>

[<Struct>]
type OptionT<'monad<option<'t>>> =
 OptionT of 'monad<option<'t>>
static member (<*>) : f: OptionT<'Monad<option<('T > 'U)>> * x: OptionT<'Monad<option<'T>> > OptionT<'Monad<option<'U>> (requires member Map and member ``<*>``)
static member (<>) : OptionT<'a1> * OptionT<'MonadPlus<option<'T>> > OptionT<'MonadPlus<option<'T>> (requires member (>>=) and member Return)
static member (>>=) : x: OptionT<'Monad<option<'T>> * f: ('T > OptionT<'Monad<option<'U>>) > OptionT<'Monad<option<'U>> (requires member (>>=) and member Return)
static member CallCC: f: (('T > OptionT<'MonadCont<'R,option<'U>>>) > OptionT<'MonadCont<'R,option<'T>>>) > OptionT<'MonadCont<'R,option<'T>>> (requires member CallCC)
static member Catch: m: OptionT<'MonadError<'E1,'T>> * h: ('E1 > OptionT<'MonadError<'E2,'T>>) > OptionT<'MonadError<'E2,'T>> (requires member Catch)
static member Delay: body: (unit > OptionT<'Monad<option<'T>>>) > OptionT<'Monad<option<'T>>> (requires member Delay)
static member LiftAsync: x: Async<'T> > OptionT<'MonadAsync<'T>> (requires member Return and member (>>=) and member Map and member LiftAsync)
static member Listen: m: OptionT<'a1> > OptionT<''MonadWriter<'Monoid, option<'T>>> (requires member (>>=) and member Return and member Listen)
static member Local: OptionT<'MonadReader<'R2,'T>> * f: ('R1 > 'R2) > OptionT<'a4> (requires member Local)
static member Pass: m: OptionT<'a1> > OptionT<'MonadWriter<'Monoid, option<'T>>> (requires member (>>=) and member Map and member Return and member Pass and member Return)
...
<summary>
Monad Transformer for Option<'T>
</summary>
type 'T list = List<'T>
<summary>The type of immutable singlylinked lists. </summary>
<remarks>See the <see cref="T:Microsoft.FSharp.Collections.ListModule" /> module for further operations related to lists.
Use the constructors <c>[]</c> and <c>::</c> (infix) to create values of this type, or
the notation <c>[1; 2; 3]</c>. Use the values in the <c>List</c> module to manipulate
values of this type, or pattern match against the values directly.
See also <a href="https://docs.microsoft.com/dotnet/fsharp/languagereference/lists">F# Language Guide  Lists</a>.
</remarks>
type unit = Unit
<summary>The type 'unit', which has only one value "()". This value is special and
always uses the representation 'null'.</summary>
<category index="1">Basic Types</category>
Multiple items
val option: f: ('g > 'h) > n: 'h > _arg1: 'g option > 'h
<summary>
Takes a function, a default value and a option value. If the option value is None, the function returns the default value.
Otherwise, it applies the function to the value inside Some and returns the result.
</summary>
<category index="0">Common Combinators</category>

type 'T option = Option<'T>
<summary>The type of optional values. When used from other CLI languages the
empty option is the <c>null</c> value. </summary>
<remarks>Use the constructors <c>Some</c> and <c>None</c> to create values of this type.
Use the values in the <c>Option</c> module to manipulate values of this type,
or pattern match against the values directly.
'None' values will appear as the value <c>null</c> to other CLI languages.
Instance methods on this type will appear as static methods to other CLI languages
due to the use of <c>null</c> as a value representation.</remarks>
<category index="3">Options</category>
val monad<'monad<'t>> : MonadFxBuilder<'monad<'t>>
<summary>
Creates a (lazy) monadic computation expression with sideeffects (see http://fsprojects.github.io/FSharpPlus/computationexpressions.html for more information)
</summary>
val printfn: format: Printf.TextWriterFormat<'T> > 'T
<summary>Print to <c>stdout</c> using the given format, and add a newline.</summary>
<param name="format">The formatter.</param>
<returns>The formatted result.</returns>
<example>See <c>Printf.printfn</c> (link: <see cref="M:Microsoft.FSharp.Core.PrintfModule.PrintFormatLine``1" />) for examples.</example>
Multiple items
val seq: sequence: seq<'T> > seq<'T>
<summary>Builds a sequence using sequence expression syntax</summary>
<param name="sequence">The input sequence.</param>
<returns>The result sequence.</returns>
<example id="seqcastexample"><code lang="fsharp">
seq { for i in 0..10 do yield (i, i*i) }
</code></example>

type seq<'T> = System.Collections.Generic.IEnumerable<'T>
<summary>An abbreviation for the CLI type <see cref="T:System.Collections.Generic.IEnumerable`1" /></summary>
<remarks>
See the <see cref="T:Microsoft.FSharp.Collections.SeqModule" /> module for further operations related to sequences.
See also <a href="https://docs.microsoft.com/dotnet/fsharp/languagereference/sequences">F# Language Guide  Sequences</a>.
</remarks>
val lazyValue: System.Lazy<int>
val a: int
val b: int
val res12: int
property System.Lazy.Value: int with get
val maybeWithSideFx: int option
union case Option.Some: Value: 'T > Option<'T>
<summary>The representation of "Value of type 'T"</summary>
<param name="Value">The input value.</param>
<returns>An option representing the value.</returns>
val b: int ref
Multiple items
val ref: value: 'T > 'T ref
<summary>Create a mutable reference cell</summary>
<param name="value">The value to contain in the cell.</param>
<returns>The created reference cell.</returns>
<example id="refexample"><code lang="fsharp">
let count = ref 0 // Creates a reference cell object with a mutable Value property
count.Value // Evaluates to 0
count.Value < 1 // Updates the value
count.Value // Evaluates to 1
</code></example>

type 'T ref = Ref<'T>
<summary>The type of mutable references. Use the functions [!] and [:=] to get and
set values of this type.</summary>
<category>Basic Types</category>
val n: unit
val incr: cell: int ref > unit
<summary>Increment a mutable reference cell containing an integer</summary>
<param name="cell">The reference cell.</param>
<example id="increxample"><code lang="fsharp">
let count = ref 99 // Creates a reference cell object with a mutable Value property
incr count // Increments our counter
count.Value // Evaluates to 100
</code></example>
val lst: int option list
union case Option.None: Option<'T>
<summary>The representation of "No value"</summary>
val maybeManyTimes: int option
val defaultValue: int
val mutable i: int
val asnNumber: Async<int>
Multiple items
module Async
from FSharpPlus
<summary>
Additional operations on Async
</summary>

type Async =
static member AsBeginEnd: computation: ('Arg > Async<'T>) > ('Arg * AsyncCallback * obj > IAsyncResult) * (IAsyncResult > 'T) * (IAsyncResult > unit)
static member AwaitEvent: event: IEvent<'Del,'T> * ?cancelAction: (unit > unit) > Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult: iar: IAsyncResult * ?millisecondsTimeout: int > Async<bool>
static member AwaitTask: task: Task<'T> > Async<'T> + 1 overload
static member AwaitWaitHandle: waitHandle: WaitHandle * ?millisecondsTimeout: int > Async<bool>
static member CancelDefaultToken: unit > unit
static member Catch: computation: Async<'T> > Async<Choice<'T,exn>>
static member Choice: computations: seq<Async<'T option>> > Async<'T option>
static member FromBeginEnd: beginAction: (AsyncCallback * obj > IAsyncResult) * endAction: (IAsyncResult > 'T) * ?cancelAction: (unit > unit) > Async<'T> + 3 overloads
static member FromContinuations: callback: (('T > unit) * (exn > unit) * (OperationCanceledException > unit) > unit) > Async<'T>
...
<summary>Holds static members for creating and manipulating asynchronous computations.</summary>
<remarks>
See also <a href="https://docs.microsoft.com/enus/dotnet/fsharp/languagereference/asynchronousworkflows">F# Language Guide  Async Workflows</a>.
</remarks>
<category index="1">Async Programming</category>

type Async<'T>
<summary>
An asynchronous computation, which, when run, will eventually produce a value of type T, or else raises an exception.
</summary>
<remarks>
This type has no members. Asynchronous computations are normally specified either by using an async expression
or the static methods in the <see cref="T:Microsoft.FSharp.Control.FSharpAsync`1" /> type.
See also <a href="https://docs.microsoft.com/enus/dotnet/fsharp/languagereference/asynchronousworkflows">F# Language Guide  Async Workflows</a>.
</remarks>
<namespacedoc><summary>
Library functionality for asynchronous programming, events and agents. See also
<a href="https://docs.microsoft.com/enus/dotnet/fsharp/languagereference/asynchronousworkflows">Asynchronous Programming</a>,
<a href="https://docs.microsoft.com/enus/dotnet/fsharp/languagereference/members/events">Events</a> and
<a href="https://docs.microsoft.com/enus/dotnet/fsharp/languagereference/lazyexpressions">Lazy Expressions</a> in the
F# Language Guide.
</summary></namespacedoc>
<category index="1">Async Programming</category>
val mutable m: ResizeArray<int>
Multiple items
module ResizeArray
from FSharpPlus
<summary>
Additional operations on ResizeArray
</summary>

type ResizeArray<'T> = System.Collections.Generic.List<'T>
<summary>An abbreviation for the CLI type <see cref="T:System.Collections.Generic.List`1" /></summary>
val i: int
System.Collections.Generic.List.Add(item: int) : unit
val e: exn
val lstNumber: int list