FSharpPlus


Monad

Defines the basic operations over a monad, a concept from a branch of mathematics known as category theory. From the perspective of an F# programmer, however, it is best to think of a monad as an abstract datatype of actions. F#+ generic computation expressions provide a convenient syntax for writing monadic expressions.


Minimal complete definition

static member Return (x: 'T) : 'Monad<'T>
static member (>>=) (x: Monad<'T>, f: 'T->Monad<'U>) : Monad<'U>

Note: return can't be used outside computation expressions, use result instead.

Other operations

static member Join (x:'Monad<'Monad<'T>>) :'Monad<'T>

Rules

return a >>= k = k a
m >>= return = m
m >>= (fun x -> k x >>= h) = (m >>= k) >>= h

Related Abstractions

Concrete implementations

From F#

From F#+

Examples

#r @"nuget: FSharpPlus"
open FSharpPlus
open FSharpPlus.Data


// Monads allow us to use our generic computation expressions

// This will return the list [11;21;12;22] which is both lists combined in different ways with the (+) operation
let lst11n21n12n22 =
    monad {
        let! x1 = [1;   2]
        let! x2 = [10; 20]
        return ((+) x1 x2) }

// This is the same example but with a non-empty list
let neLst11n21n12n22 = 
    monad {
        let! x1 = { NonEmptyList.Head =  1; Tail =  [2] }
        let! x2 = { NonEmptyList.Head = 10; Tail = [20] }
        return ((+) x1 x2)}

// And now an example with options
let some14 =
    monad {
        let! x1 = Some 4
        let! x2 = tryParse "10"
        return ((+) x1 x2) }



// MONAD TRANSFORMERS
// ==================
//
// Monads do not compose directly, we need to use Monad Transformers
let fn : ResultT<Reader<int,Result<_,string>>> = 
    monad {
       let! x1 = lift ask
       let! x2 = 
           if x1 > 0 then result 1
           else ResultT (result (Error "Negative value"))
       return x1 + x2
    }

let x = (fn |> ResultT.run |> Reader.run) 10
// Result<int,string> = Ok 11
let y = (fn |> ResultT.run |> Reader.run) -1
// Result<int,string> = Error "Negative value"
// The following example comes from Haskell
// async is used instead of IO

open System

// First let's define some functions we'll use later
let getLine    = async { return Console.ReadLine () }
let putStrLn x = async { printfn "%s" x }
let isValid s =
    String.length s >= 8
        && String.exists Char.IsLetter s
        && String.exists Char.IsNumber s
        && String.exists Char.IsPunctuation s

let decodeError = function
    | -1 -> "Password not valid"
    | _  -> "Unknown"


// Now the following functions compose the Error monad with the Async one.

let getValidPassword : ResultT<_> =
    monad {
        let! s = liftAsync getLine
        if isValid s then return s
        else return! throw -1}
    </catch/>
        (fun s -> throw ("The error was: " + decodeError s))

let askPassword = monad {
    do! lift <| putStrLn "Insert your new password:"
    let! value = getValidPassword
    //do! lift <| putStrLn "Storing in database..."
    return value}

//try -> Async.RunSynchronously (ResultT.run askPassword)


// After getting used to monadic CEs it's natural
// to feel the need to combine monads
// (from https://stackoverflow.com/a/37900264 )

module CombineWriterWithResult =
    
    let divide5By = function
        | 0.0 -> Error "Divide by zero"
        | x   -> Ok (5.0 / x)

    let eitherConv logSuccessF logFailF f v =
        ResultT <|
            match f v with
            | Ok a -> Writer(Ok a, ["Success: " + logSuccessF a])
            | Error b -> Writer(Error b, ["ERROR: "   + logFailF b])

    let ew = monad {
        let! x = eitherConv (sprintf "%f") (sprintf "%s") divide5By 6.0
        let! y = eitherConv (sprintf "%f") (sprintf "%s") divide5By 3.0
        let! z = eitherConv (sprintf "%f") (sprintf "%s") divide5By 0.0
        return (x, y, z) }

    let (_, log) = ew |> ResultT.run |> Writer.run


// You can also stack monad transformers.

// A monad transformer and a monad is itself a monad, so you can pass that into another monad transformer.
// For example, below we are stacking them like:
// type Example = ReaderT<DateTime, ResultT<Writer<string list, Result<string * string * string, string>>>>)

// Catch and throw is generic over all monad transformers in F#+ so catch works in this example
// because there is a Result in the stack. We use it here to consolidate Result's 'TError.

module CombineReaderWithWriterWithResult =

    let divide5By : float -> Result<float, string> = function
        | 0.0 -> Error "Divide by zero"
        | x   -> Ok (5.0 / x)

    let otherDivide5By : float -> Result<float, unit>  = function
        | 0.0 -> Error ()
        | x   -> Ok (5.0 / x)

    let eitherConv f v =
        ReaderT <| fun (now : System.DateTime) ->
        ResultT <|
            match f v with
            | Ok a    -> Writer(Ok a,    [sprintf "Success at %s: %A" (now.ToString "o") a])
            | Error b -> Writer(Error b, [sprintf "ERROR at %s: %A"   (now.ToString "o") b])

    let divide = monad {
        let! w = eitherConv divide5By       6.0
        let! x = eitherConv divide5By       3.0
        let! y = eitherConv divide5By       0.0
        let! z = eitherConv otherDivide5By  0.0 </catch/> (throw << (fun _ -> "Unknown error"))

        return (w, x, y, z) }

    let run expr = ReaderT.run expr >> ResultT.run >> Writer.run

    let (_, log) = run divide DateTime.UtcNow


// Many popular F# libraries are in fact an instantiation of a specific monad combination.
// The following example demonstrate how to code a mini-Suave lib in a few lines

module Suave =
    // setup something that reminds us of what Suave can work with
    // this is an overly simplified model of Suave in order to show how OptionT can be used 
    // in conjunction with generic Kleisli composition (fish) operator
    type WebPart<'a> = 'a -> OptionT<Async<'a option>>
    let inline succeed x = async.Return (Some x)

    module Http =
        type HttpResponse = { status: int; content: string }
        type HttpRequest  = { url: Uri; ``method``: string }
        type HttpContext  = { request: HttpRequest; response: HttpResponse }

    module Successful =
        open Http
        let private withStatusCode statusCode s =
            OptionT << fun ctx -> { ctx with response = { ctx.response with status = statusCode; content = s }} |> succeed
        let OK s = withStatusCode 200 s
        let BAD_REQUEST s = withStatusCode 400 s

    module Filters =
        open Http
        let ``method`` (m: string) =
            OptionT << fun (x: HttpContext) -> async.Return (if (m = x.request.``method``) then Some x else None)
        let GET  (x : HttpContext) = ``method`` "GET" x
        let POST (x : HttpContext) = ``method`` "POST" x
  
        let path s =
            OptionT << fun (x: HttpContext) -> async.Return (if (s = x.request.url.AbsolutePath) then Some x else None)

    // Stub implementations: here you can plug Fleece or another similar Json library
    let toJson o : string  = failwith "Not implemented"
    let ofJson (s: string) = failwith "Not implemented"

    module Request =
        let tryGet _s (_r: Http.HttpRequest) = Ok "FORM VALUE"

    let authenticated (f: Http.HttpContext -> int -> OptionT<Async<'a option>>) =
        // we assume that authenticated executes f only if auth, otherwise returns 401
        // we fake it as:
        fun (ctx: Http.HttpContext) -> f ctx -1

    // Usage:
    open Successful
    open Filters
    type Note = { id: int; text: string }
    type NoteList = { notes: Note list; offset: int; chunk: int; total: int }
    type IDb =
        abstract member getUserNotes: int -> Async<NoteList>
        abstract member addUserNote: int -> string -> Async<Note>
    type OverviewViewModel = { myNotes: Note list }
    let app (db: IDb) =
        let overview =
            GET >=> (authenticated <| fun ctx userId ->
                monad {
                  let! res = lift (db.getUserNotes userId)
                  let ovm = toJson { myNotes = res.notes }
                  return! OK ovm ctx
                })
        let register =
            POST >=> (authenticated <| fun ctx userId ->
                monad {
                  match ctx.request |> Request.tryGet "text" with 
                  | Ok text ->
                      let! newNote = lift (db.addUserNote userId text)
                      let rvm = toJson newNote
                      return! OK rvm ctx
                  | Error msg -> 
                      return! BAD_REQUEST msg ctx
                })
        choice [
            path "/" >=> (OK "/")
            path "/note" >=> register
            path "/notes" >=> overview
        ]

Recommended reading

namespace FSharpPlus
namespace FSharpPlus.Data
val lst11n21n12n22: int list
val monad<'monad<'t>> : MonadFxBuilder<'monad<'t>>
<summary> Creates a (lazy) monadic computation expression with side-effects (see http://fsprojects.github.io/FSharpPlus/computation-expressions.html for more information) </summary>
val x1: int
val x2: int
val neLst11n21n12n22: NonEmptyList<int>
Multiple items
module NonEmptyList from FSharpPlus.Data
<summary> Basic operations on NonEmptyList </summary>

--------------------
type NonEmptyList<'t> = { Head: 't Tail: 't list } interface NonEmptySeq<'t> interface IReadOnlyList<'t> interface IReadOnlyCollection<'t> interface IEnumerable interface IEnumerable<'t> static member (+) : NonEmptyList<'a1> * x: NonEmptyList<'a1> -> NonEmptyList<'a1> static member (<*>) : f: NonEmptyList<('T -> 'U)> * x: NonEmptyList<'T> -> NonEmptyList<'U> static member (=>>) : s: NonEmptyList<'a1> * g: (NonEmptyList<'a1> -> 'b) -> NonEmptyList<'b> static member (>>=) : NonEmptyList<'a1> * f: ('a1 -> NonEmptyList<'b>) -> NonEmptyList<'b> static member Choice: source: NonEmptyList<'Alt<'T>> -> 'Alt<'T> (requires member IsAltLeftZero and member ``<|>``) ...
<summary> A type-safe list that contains at least one element. </summary>
val some14: int option
union case Option.Some: Value: 'T -> Option<'T>
val tryParse: value: string -> 'T option (requires member TryParse)
<summary> Converts to a value from its string representation. Returns None if the convertion doesn't succeed. </summary>
<category index="21">Converter</category>
namespace System
val getLine: Async<string>
val async: AsyncBuilder
type Console = static member Beep: unit -> unit + 1 overload static member Clear: unit -> unit static member GetCursorPosition: unit -> struct (int * int) static member MoveBufferArea: sourceLeft: int * sourceTop: int * sourceWidth: int * sourceHeight: int * targetLeft: int * targetTop: int -> unit + 1 overload static member OpenStandardError: unit -> Stream + 1 overload static member OpenStandardInput: unit -> Stream + 1 overload static member OpenStandardOutput: unit -> Stream + 1 overload static member Read: unit -> int static member ReadKey: unit -> ConsoleKeyInfo + 1 overload static member ReadLine: unit -> string ...
<summary>Represents the standard input, output, and error streams for console applications. This class cannot be inherited.</summary>
Console.ReadLine() : string
val putStrLn: x: string -> Async<unit>
val x: string
val printfn: format: Printf.TextWriterFormat<'T> -> 'T
val isValid: s: string -> bool
val s: string
Multiple items
type String = interface IEnumerable<char> interface IEnumerable interface ICloneable interface IComparable interface IComparable<string> interface IConvertible interface IEquatable<string> new: value: nativeptr<char> -> unit + 8 overloads member Clone: unit -> obj member CompareTo: value: obj -> int + 1 overload ...
<summary>Represents text as a sequence of UTF-16 code units.</summary>

--------------------
String(value: nativeptr<char>) : String
String(value: char array) : String
String(value: ReadOnlySpan<char>) : String
String(value: nativeptr<sbyte>) : String
String(c: char, count: int) : String
String(value: nativeptr<char>, startIndex: int, length: int) : String
String(value: char array, startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : String
val length: str: string -> int
val exists: predicate: (char -> bool) -> str: string -> bool
[<Struct>] type Char = member CompareTo: value: char -> int + 1 overload member Equals: obj: char -> bool + 1 overload member GetHashCode: unit -> int member GetTypeCode: unit -> TypeCode member ToString: unit -> string + 2 overloads static member ConvertFromUtf32: utf32: int -> string static member ConvertToUtf32: highSurrogate: char * lowSurrogate: char -> int + 1 overload static member GetNumericValue: c: char -> float + 1 overload static member GetUnicodeCategory: c: char -> UnicodeCategory + 1 overload static member IsAscii: c: char -> bool ...
<summary>Represents a character as a UTF-16 code unit.</summary>
Char.IsLetter(c: char) : bool
Char.IsLetter(s: string, index: int) : bool
Char.IsNumber(c: char) : bool
Char.IsNumber(s: string, index: int) : bool
Char.IsPunctuation(c: char) : bool
Char.IsPunctuation(s: string, index: int) : bool
val decodeError: _arg1: int -> string
val getValidPassword: ResultT<Async<Result<string,string>>>
Multiple items
union case ResultT.ResultT: 'monad<Result<'t,'e>> -> ResultT<'monad<Result<'t,'e>>>

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

--------------------
[<Struct>] type ResultT<'monad<Result<'t,'e>>> = | ResultT of 'monad<Result<'t,'e>> static member (+) : ResultT<'a1> * ResultT<'a5> -> ResultT<'MonadPlus<Result<'U,'E>>> (requires member (>>=) and member (>>=) and member Return and member ``+`` and member ``+``) static member (<*>) : f: ResultT<'Monad<Result<('T -> 'U),'E>>> * x: ResultT<'Monad<Result<'T,'E>>> -> ResultT<'Monad<Result<'U,'E>>> (requires member Map and member ``<*>``) static member (<|>) : ResultT<'a1> * ResultT<'a5> -> ResultT<'MonadPlus<Result<'U,'E>>> (requires member (>>=) and member Return and member (>>=) and member ``+``) static member (>=>) : f: ('T -> ResultT<'Monad<Result<'U, 'E>>) * g: ('U -> ResultT<'Monad<Result<'V, 'E>>) -> ('T -> ResultT<'Monad<Result<'V, 'E>>) (requires member (>>=) and member Return) static member (>>=) : x: ResultT<'Monad<Result<'T,'E>>> * f: ('T -> ResultT<'Monad<Result<'U,'E>>>) -> ResultT<'Monad<Result<'U,'E>>> (requires member (>>=) and member Return) static member CallCC: f: (('T -> ResultT<'MonadCont<'R,Result<'U,'E>>>) -> ResultT<'MonadCont<'R, Result<'T,'E>>>) -> ResultT<'MonadCont<'R, Result<'T,'E>>> (requires member CallCC) static member Catch: ResultT<'Monad<Result<'T, 'E1>>> * f: ('E1 -> ResultT<'Monad<Result<'T, 'E2>>>) -> ResultT<'Monad<Result<'T, 'E2>>> (requires member (>>=) and member Return) static member Delay: body: (unit -> ResultT<'Monad<Result<'T,'E>>>) -> ResultT<'Monad<Result<'T,'E>>> (requires member Delay) static member LiftAsync: x: Async<'T> -> ResultT<'MonadAsync<'T>> (requires member Return and member (>>=) and member Map and member LiftAsync) static member Listen: m: ResultT<'a1> -> ResultT<'MonadWriter<'Monoid,Result<'T*'Monoid,'E>>> (requires member (>>=) and member Return and member Listen) ...
<summary> Monad Transformer for Result&lt;'T, 'E&gt; </summary>
val liftAsync: x: Async<'T> -> 'MonadAsync<'T> (requires member LiftAsync)
<summary> A specialized lift for Async&lt;'T&gt; which is able to bring an Async value from any depth of monad-layers. </summary>
<category index="18">Monad Transformers</category>
val throw: error: 'E -> ''MonadError<'E,'T> (requires member Throw)
<summary> Throws an error value inside the Error monad. </summary>
<category index="18">Monad Transformers</category>
val catch: value: ''MonadError<'E1,'T> -> handler: ('E1 -> ''MonadError<'E2,'T>) -> ''MonadError<'E2,'T> (requires member Catch)
<summary> Executes a handler when the value contained in the Error monad represents an error. This is bindError flipped, which makes it useful when used as an operator. </summary>
<example><code> let doSomeOperation x = ResultT &lt;| async { if x &lt; 10 then return Ok 10 else return Error "failure" } doSomeOperation &lt;/catch/&gt; (fun s -&gt; throw ("The error was: " + s)) </code></example>
<category index="18">Monad Transformers</category>
val s: int
val askPassword: ResultT<Async<Result<string,string>>>
val lift: x: 'Monad<'T> -> 'MonadTrans<'Monad<'T>> (requires member Lift)
<summary> Lifts a computation from the inner monad to the constructed monad. </summary>
<category index="18">Monad Transformers</category>
val value: string
val divide5By: _arg1: float -> Result<float,string>
union case Result.Error: ErrorValue: 'TError -> Result<'T,'TError>
val x: float
union case Result.Ok: ResultValue: 'T -> Result<'T,'TError>
val eitherConv: logSuccessF: ('a -> string) -> logFailF: ('b -> string) -> f: ('c -> Result<'a,'b>) -> v: 'c -> ResultT<Writer<string list,Result<'a,'b>>>
val logSuccessF: ('a -> string)
val logFailF: ('b -> string)
val f: ('c -> Result<'a,'b>)
val v: 'c
val a: 'a
Multiple items
union case Writer.Writer: ('t * 'monoid) -> Writer<'monoid,'t>

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

--------------------
[<Struct>] type Writer<'monoid,'t> = | Writer of ('t * 'monoid) static member ( *> ) : x: Writer<'Monoid,'T> * y: Writer<'Monoid,'U> -> Writer<'Monoid,'U> (requires member ``+``) static member (<!>) : f: ('T -> 'U) * x: Writer<'Monoid,'T> -> Writer<'Monoid,'U> static member ( <* ) : x: Writer<'Monoid,'U> * y: Writer<'Monoid,'T> -> Writer<'Monoid,'U> (requires member ``+``) static member (<*>) : f: Writer<'Monoid,('T -> 'U)> * x: Writer<'Monoid,'T> -> Writer<'Monoid,'U> (requires member ``+``) static member (=>>) : g: Writer<'T,'W> * f: (Writer<'T,'W> -> 'U) -> Writer<'U,'W> static member (>=>) : f: ('T -> Writer<'Monoid,'U>) * g: ('U -> Writer<'Monoid,'V>) -> ('T -> Writer<'Monoid,'V>) (requires member ``+``) static member (>>=) : x: Writer<'Monoid,'T> * f: ('T -> Writer<'Monoid,'U>) -> Writer<'Monoid,'U> (requires member ``+``) static member Extract: Writer<'T,'W> -> 'T static member Listen: m: Writer<'Monoid,'T> -> Writer<'Monoid,('T * 'Monoid)> static member Pass: m: Writer<'Monoid,('T * ('Monoid -> 'Monoid))> -> Writer<'Monoid,'T> ...
<summary> Computation type: Computations which produce a stream of data in addition to the computed values. <para /> Binding strategy: Combines the outputs of the subcomputations using <c>mappend</c>. <para /> Useful for: Logging, or other computations that produce output "on the side". </summary>
val b: 'b
val ew: ResultT<Writer<string list,Result<(float * float * float),string>>>
val sprintf: format: Printf.StringFormat<'T> -> 'T
val y: float
val z: float
val log: string list
val run: ResultT<'Monad<Result<'T,'E>>> -> 'Monad<Result<'T,'E>>
val run: Writer<'Monoid,'T> -> 'T * 'Monoid
<summary> Unwraps a writer computation as a (result, output) pair. (The inverse of Writer.) </summary>
Multiple items
val float: value: 'T -> float (requires member op_Explicit)

--------------------
type float = Double

--------------------
type float<'Measure> = float
Multiple items
module Result from FSharpPlus.Data
<summary> Additional operations on Result </summary>

--------------------
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
Multiple items
val string: value: 'T -> string

--------------------
type string = String
val otherDivide5By: _arg1: float -> Result<float,unit>
type unit = Unit
val eitherConv: f: ('a -> Result<'b,'c>) -> v: 'a -> ReaderT<DateTime,ResultT<Writer<string list,Result<'b,'c>>>>
val f: ('a -> Result<'b,'c>)
val v: 'a
Multiple items
union case ReaderT.ReaderT: ('r -> 'monad<'t>) -> ReaderT<'r,'monad<'t>>

--------------------
module ReaderT from FSharpPlus.Data
<summary> Basic operations on Reader </summary>

--------------------
[<Struct>] type ReaderT<'r,'monad<'t>> = | ReaderT of ('r -> 'monad<'t>) static member ( *> ) : x: ReaderT<'R,'Monad<'T>> * y: ReaderT<'R,'Monad<'U>> -> ReaderT<'R,'Monad<'U>> (requires member Map and member ``<*>``) static member (<!>) : f: ('T -> 'U) * x: ReaderT<'R,'Monad<'T>> -> ReaderT<'R,'Monad<'U>> (requires member Map) static member ( <* ) : x: ReaderT<'R,'Monad<'U>> * y: ReaderT<'R,'Monad<'T>> -> ReaderT<'R,'Monad<'U>> (requires member Map and member ``<*>``) static member (<*>) : f: ReaderT<'R,'Monad<'T -> 'U>> * x: ReaderT<'R,'Monad<'T>> -> ReaderT<'R,'Monad<'U>> (requires member ``<*>``) static member (<|>) : ReaderT<'R,'MonadPlus<'T>> * ReaderT<'R,'MonadPlus<'T>> -> ReaderT<'R,'MonadPlus<'T>> (requires member ``<|>``) static member (>=>) : f: ('T -> Reader<'R,'U>) * g: ('U -> Reader<'R,'V>) -> ('T -> Reader<'R,'V>) + 1 overload static member (>>=) : x: ReaderT<'R,'Monad<'T>> * f: ('T -> ReaderT<'R,'Monad<'U>>) -> ReaderT<'R,'Monad<'U>> (requires member (>>=)) static member CallCC: f: (('T -> ReaderT<'R,'MonadCont<'C,'U>>) -> ReaderT<'R,'MonadCont<'C,'T>>) -> ReaderT<'R,'MonadCont<'C,'T>> (requires member CallCC) static member Catch: m: ReaderT<'R,'MonadError<'E1,'T>> * h: ('E1 -> ReaderT<'R,'MonadError<'E2,'T>>) -> ReaderT<'R,'MonadError<'E2,'T>> (requires member Catch) static member Delay: body: (unit -> ReaderT<'R,'Monad<'T>>) -> ReaderT<'R,'Monad<'T>> (requires member Delay) ...
<summary> Monad Transformer for Reader&lt;'R, 'T&gt; </summary>
val now: DateTime
Multiple items
[<Struct>] type DateTime = new: year: int * month: int * day: int -> unit + 14 overloads member Add: value: TimeSpan -> DateTime member AddDays: value: float -> DateTime member AddHours: value: float -> DateTime member AddMicroseconds: value: float -> DateTime member AddMilliseconds: value: float -> DateTime member AddMinutes: value: float -> DateTime member AddMonths: months: int -> DateTime member AddSeconds: value: float -> DateTime member AddTicks: value: int64 -> DateTime ...
<summary>Represents an instant in time, typically expressed as a date and time of day.</summary>

--------------------
DateTime ()
   (+0 other overloads)
DateTime(ticks: int64) : DateTime
   (+0 other overloads)
DateTime(ticks: int64, kind: DateTimeKind) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: DateTimeKind) : DateTime
   (+0 other overloads)
val a: 'b
DateTime.ToString() : string
DateTime.ToString(format: string) : string
DateTime.ToString(provider: IFormatProvider) : string
DateTime.ToString(format: string, provider: IFormatProvider) : string
val b: 'c
val divide: ReaderT<DateTime,ResultT<Writer<string list,Result<(float * float * float * float),string>>>>
val w: float
val run: expr: ReaderT<'a,ResultT<Writer<'b,'c>>> -> ('a -> 'c * 'b)
val expr: ReaderT<'a,ResultT<Writer<'b,'c>>>
val run: ReaderT<'R,'Monad<'T>> -> ('R -> 'Monad<'T>)
property DateTime.UtcNow: DateTime with get
<summary>Gets a <see cref="T:System.DateTime" /> object that is set to the current date and time on this computer, expressed as the Coordinated Universal Time (UTC).</summary>
<returns>An object whose value is the current UTC date and time.</returns>
module Suave from Abstraction-monad
type WebPart<'a> = 'a -> OptionT<Async<'a option>>
'a
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 (+) : OptionT<'a1> * OptionT<'MonadPlus<option<'T>> -> OptionT<'MonadPlus<option<'T>> (requires member (>>=) and member (>>=) and member Return and member ``+``) 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 (>=>) : f: ('T -> OptionT<'Monad<option<'U>>) * g: ('U -> OptionT<'Monad<option<'V>>) -> ('T -> OptionT<'Monad<option<'V>>) (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) ...
<summary> Monad Transformer for Option&lt;'T&gt; </summary>
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> ...

--------------------
type Async<'T>
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>
val succeed: x: 'a -> Async<'a option>
val x: 'a
member AsyncBuilder.Return: value: 'T -> Async<'T>
type HttpResponse = { status: int content: string }
HttpResponse.status: int
Multiple items
val int: value: 'T -> int (requires member op_Explicit)

--------------------
type int = int32

--------------------
type int<'Measure> = int
HttpResponse.content: string
type HttpRequest = { url: Uri method: string }
HttpRequest.url: Uri
Multiple items
type Uri = interface ISerializable new: uriString: string -> unit + 6 overloads member Equals: comparand: obj -> bool member GetComponents: components: UriComponents * format: UriFormat -> string member GetHashCode: unit -> int member GetLeftPart: part: UriPartial -> string member IsBaseOf: uri: Uri -> bool member IsWellFormedOriginalString: unit -> bool member MakeRelative: toUri: Uri -> string member MakeRelativeUri: uri: Uri -> Uri ...
<summary>Provides an object representation of a uniform resource identifier (URI) and easy access to the parts of the URI.</summary>

--------------------
Uri(uriString: string) : Uri
Uri(uriString: string, creationOptions: inref<UriCreationOptions>) : Uri
Uri(uriString: string, uriKind: UriKind) : Uri
Uri(baseUri: Uri, relativeUri: string) : Uri
Uri(baseUri: Uri, relativeUri: Uri) : Uri
type HttpContext = { request: HttpRequest response: HttpResponse }
HttpContext.request: HttpRequest
HttpContext.response: HttpResponse
module Http from Abstraction-monad.Suave
val private withStatusCode: statusCode: int -> s: string -> (HttpContext -> OptionT<Async<HttpContext option>>)
val statusCode: int
val ctx: HttpContext
val OK: s: string -> (HttpContext -> OptionT<Async<HttpContext option>>)
val BAD_REQUEST: s: string -> (HttpContext -> OptionT<Async<HttpContext option>>)
val m: string
val x: HttpContext
union case Option.None: Option<'T>
val GET: x: HttpContext -> OptionT<Async<HttpContext option>>
val POST: x: HttpContext -> OptionT<Async<HttpContext option>>
val path: s: string -> (HttpContext -> OptionT<Async<HttpContext option>>)
property Uri.AbsolutePath: string with get
<summary>Gets the absolute path of the URI.</summary>
<exception cref="T:System.InvalidOperationException">This instance represents a relative URI, and this property is valid only for absolute URIs.</exception>
<returns>The absolute path to the resource.</returns>
val toJson: o: 'a -> string
val o: 'a
val failwith: message: string -> 'T
val ofJson: s: string -> 'a
val tryGet: _s: 'a -> _r: Http.HttpRequest -> Result<string,'b>
val _s: 'a
val _r: Http.HttpRequest
val authenticated: f: (Http.HttpContext -> int -> OptionT<Async<'a option>>) -> ctx: Http.HttpContext -> OptionT<Async<'a option>>
val f: (Http.HttpContext -> int -> OptionT<Async<'a option>>)
val ctx: Http.HttpContext
module Successful from Abstraction-monad.Suave
module Filters from Abstraction-monad.Suave
type Note = { id: int text: string }
Note.id: int
Note.text: string
type NoteList = { notes: Note list offset: int chunk: int total: int }
NoteList.notes: Note list
type 'T list = List<'T>
NoteList.offset: int
NoteList.chunk: int
NoteList.total: int
type IDb = abstract addUserNote: int -> string -> Async<Note> abstract getUserNotes: int -> Async<NoteList>
type OverviewViewModel = { myNotes: Note list }
OverviewViewModel.myNotes: Note list
val app: db: IDb -> (Http.HttpContext -> OptionT<Async<Http.HttpContext option>>)
val db: IDb
val overview: (Http.HttpContext -> OptionT<Async<Http.HttpContext option>>)
val GET: x: Http.HttpContext -> OptionT<Async<Http.HttpContext option>>
val userId: int
val res: NoteList
abstract IDb.getUserNotes: int -> Async<NoteList>
val ovm: string
val OK: s: string -> (Http.HttpContext -> OptionT<Async<Http.HttpContext option>>)
val register: (Http.HttpContext -> OptionT<Async<Http.HttpContext option>>)
val POST: x: Http.HttpContext -> OptionT<Async<Http.HttpContext option>>
Http.HttpContext.request: Http.HttpRequest
module Request from Abstraction-monad.Suave
val text: string
val newNote: Note
abstract IDb.addUserNote: int -> string -> Async<Note>
val rvm: string
val msg: string
val BAD_REQUEST: s: string -> (Http.HttpContext -> OptionT<Async<Http.HttpContext option>>)
val choice: x: 'Foldable<'Alternative<'T>> -> 'Alternative<'T>> (requires member Choice)
<summary> Reduces using alternative operator `&lt;|&gt;`. </summary>
<category index="23">Additional Functions</category>
val path: s: string -> (Http.HttpContext -> OptionT<Async<Http.HttpContext option>>)