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 @"../../src/FSharpPlus/bin/Release/net45/FSharpPlus.dll"

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 WebPart =
        /// Comment from <a href="https://github.com/SuaveIO/suave/blob/v2.4.3/src/Suave/WebPart.fsi#L39-L42">WebPart.fsi</a>
        /// Entry-point for composing the applicative routes of the http application,
        /// by iterating the options, applying the context, arg, to the predicate
        /// from the list of options, until there's a match/a Some(x) which can be
        /// run.
        let choose (options: WebPart<'a> list) = fun x -> choice (List.map ((|>) x) options)

    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
                })
        WebPart.choose [ path "/" >=> (OK "/")
                         path "/note" >=> register
                         path "/notes" >=> overview ]
namespace FSharpPlus
namespace FSharpPlus.Data
val lst11n21n12n22 : int list
val monad<'monad<'t>> : MonadFxBuilder<'monad<'t>>
val x1 : int
val x2 : int
val neLst11n21n12n22 : NonEmptyList<int>
Multiple items
module NonEmptyList

from FSharpPlus.Data

--------------------
type NonEmptyList<'t> =
  { Head: 't
    Tail: 't list }
    interface NonEmptySeq<'t>
    interface IReadOnlyList<'t>
    interface IReadOnlyCollection<'t>
    interface IEnumerable
    interface IEnumerable<'t>
    member GetSlice : (int option * int option -> NonEmptyList<'t>)
    member Item : (int -> 't)
    member Length : int
    static member Choice : source:NonEmptyList<'Alt<'T>> -> 'Alt<'T> (requires member IsAltLeftZero and member ( <|> ))
    static member Duplicate : s:NonEmptyList<'a> * _impl:Duplicate -> NonEmptyList<NonEmptyList<'a>>
    ...
val some14 : int option
union case Option.Some: Value: 'T -> Option<'T>
val tryParse : value:string -> 'b option (requires member TryParse)
namespace System
val getLine : Async<string>
val async : AsyncBuilder
type Console =
  static member BackgroundColor : ConsoleColor with get, set
  static member Beep : unit -> unit + 1 overload
  static member BufferHeight : int with get, set
  static member BufferWidth : int with get, set
  static member CapsLock : bool
  static member Clear : unit -> unit
  static member CursorLeft : int with get, set
  static member CursorSize : int with get, set
  static member CursorTop : int with get, set
  static member CursorVisible : bool with get, set
  ...
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 =
  new : value:char[] -> string + 8 overloads
  member Chars : int -> char
  member Clone : unit -> obj
  member CompareTo : value:obj -> int + 1 overload
  member Contains : value:string -> bool + 3 overloads
  member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
  member EndsWith : value:string -> bool + 3 overloads
  member EnumerateRunes : unit -> StringRuneEnumerator
  member Equals : obj:obj -> bool + 2 overloads
  member GetEnumerator : unit -> CharEnumerator
  ...

--------------------
String(value: char []) : String
String(value: nativeptr<char>) : String
String(value: nativeptr<sbyte>) : String
String(value: ReadOnlySpan<char>) : String
String(c: char, count: int) : String
String(value: char [], startIndex: int, length: int) : String
String(value: nativeptr<char>, 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
type Char =
  struct
    member CompareTo : value:obj -> int + 1 overload
    member Equals : obj:obj -> bool + 1 overload
    member GetHashCode : unit -> int
    member GetTypeCode : unit -> TypeCode
    member ToString : unit -> string + 1 overload
    static val MaxValue : char
    static val MinValue : char
    static member ConvertFromUtf32 : utf32:int -> string
    static member ConvertToUtf32 : highSurrogate:char * lowSurrogate:char -> int + 1 overload
    static member GetNumericValue : c:char -> float + 1 overload
    ...
  end
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

--------------------
[<Struct>]
type ResultT<'monad<'result<'t,'e>>> =
  | ResultT of 'monad<'result<'t,'e>>
    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<'MonadError<'E1,'T>> * 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<'a2> (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)
    static member Local : ResultT<'MonadReader<'R2,Result<'R2,'E>>> * f:('R1 -> 'R2) -> ResultT<'a4> (requires member Local)
    static member Pass : m:ResultT<'a1> -> ResultT<'MonadWriter<'Monoid,Result<'T,'E>>> (requires member ( >>= ) and member Map and member Return and member Pass and member Return)
    static member Put : x:'S -> ResultT<'MonadState<'S,Result<_,'E>>> (requires member Return and member ( >>= ) and member Map and member Put)
    static member Return : x:'T -> ResultT<'Monad<'Result<'T,'E>>> (requires member Return)
    static member Tell : w:'Monoid -> ResultT<'Writer<'Monoid,Result<unit,'E>>> (requires member Return and member ( >>= ) and member Map and member Tell)
    ...
val liftAsync : x:Async<'T> -> 'MonadAsync<'T> (requires member LiftAsync)
val throw : error:'E -> ''MonadError<'E,'T> (requires member Throw)
val catch : value:''MonadError<'E1,'T> -> handler:('E1 -> ''MonadError<'E2,'T>) -> ''MonadError<'E2,'T> (requires member Catch)
val s : int
val askPassword : ResultT<Async<Result<string,string>>>
val lift : x:'Monad<'T> -> 'MonadTrans<'Monad<'T>> (requires member Lift)
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

--------------------
[<Struct>]
type Writer<'monoid,'t> =
  | Writer of ('t * 'monoid)
    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>
    static member Return : x:'T -> Writer<'Monoid,'T> (requires member Zero)
    static member Tell : w:'Monoid -> Writer<'Monoid,unit>
    static member ( =>> ) : g:Writer<'T,'W> * f:(Writer<'T,'W> -> 'U) -> Writer<'U,'W>
    static member ( >>= ) : x:Writer<'Monoid,'T> * f:('T -> Writer<'Monoid,'U>) -> Writer<'Monoid,'U> (requires member ( + ))
    static member ( <*> ) : f:Writer<'Monoid,('T -> 'U)> * x:Writer<'Monoid,'T> -> Writer<'Monoid,'U> (requires member ( + ))
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
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

--------------------
module Result

from FSharpPlus

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

--------------------
[<Struct>]
type ReaderT<'r,'monad<'t>> =
  | ReaderT of ('r -> 'monad<'t>)
    static member CallCC : f:(('T -> ReaderT<'R,Cont<'a4,'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,'a4> (requires member Delay)
    static member LiftAsync : x:Async<'T> -> ReaderT<'R,'MonadAsync<'T>> (requires member LiftAsync)
    static member Listen : ReaderT<'R,'a3> -> ReaderT<'R,'MonadWriter<'Monoid,'T*'Monoid>> (requires member Listen)
    static member Local : ReaderT<'R2,'Monad<'T>> * f:('R1 -> 'R2) -> ReaderT<'R1,'Monad<'T>>
    static member Pass : ReaderT<'R,'a3> -> ReaderT<'R,'MonadWriter<'Monoid,'T>> (requires member Pass)
    static member Put : x:'a2 -> ReaderT<'R,'MonadState<'S, unit>> (requires member Put)
    static member Return : x:'T -> ReaderT<'R,'Monad<'T>> (requires member Return)
    static member Tell : w:'a2 -> ReaderT<'R,'MonadWriter<'Monoid,unit>> (requires member Tell)
    ...
val now : DateTime
Multiple items
type DateTime =
  struct
    new : ticks:int64 -> DateTime + 10 overloads
    member Add : value:TimeSpan -> DateTime
    member AddDays : value:float -> DateTime
    member AddHours : 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
    member AddYears : value:int -> DateTime
    ...
  end

--------------------
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
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
module Suave

from Abstraction-monad
type WebPart<'a> = 'a -> OptionT<Async<'a option>>
Multiple items
union case OptionT.OptionT: 'monad<option<'t>> -> OptionT<'monad<option<'t>>>

--------------------
module OptionT

from FSharpPlus.Data

--------------------
[<Struct>]
type OptionT<'monad<option<'t>>> =
  | OptionT of 'monad<option<'t>>
    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)
    static member Put : x:'S -> OptionT<'MonadState<unit,'S>> (requires member Return and member ( >>= ) and member Map and member Put)
    static member Return : x:'T -> OptionT<'Monad<option<'T>> (requires member Return)
    static member Tell : w:'Monoid -> OptionT<'MonadWriter<'Monoid, unit>> (requires member Return and member ( >>= ) and member Map and member Tell)
    ...
Multiple items
module Async

from FSharpPlus

--------------------
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 -> Async<unit>
  static member AwaitTask : task:Task<'T> -> Async<'T>
  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>
  ...

--------------------
type Async<'T> =
Multiple items
val option : f:('g -> 'h) -> n:'h -> _arg1:'g option -> 'h

--------------------
type 'T option = Option<'T>
val succeed : x:'a -> Async<'a option>
val x : 'a
val choose : options:WebPart<'a> list -> x:'a -> OptionT<Async<'a option>>


 Comment from <a href="https://github.com/SuaveIO/suave/blob/v2.4.3/src/Suave/WebPart.fsi#L39-L42">WebPart.fsi</a>
 Entry-point for composing the applicative routes of the http application,
 by iterating the options, applying the context, arg, to the predicate
 from the list of options, until there's a match/a Some(x) which can be
 run.
val options : WebPart<'a> list
type 'T list = List<'T>
val choice : x:'Foldable<'Alternative<'T>> -> 'Alternative<'T>> (requires member Choice)
Multiple items
module List

from FSharpPlus.Data

--------------------
module List

from FSharpPlus

--------------------
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
    interface IReadOnlyList<'T>
    interface IReadOnlyCollection<'T>
    interface IEnumerable
    interface IEnumerable<'T>
    member GetSlice : startIndex:int option * endIndex:int option -> 'T list
    member Head : 'T
    member IsEmpty : bool
    member Item : index:int -> 'T with get
    member Length : int
    member Tail : 'T list
    ...
val map : mapping:('T -> 'U) -> list:'T list -> 'U list
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 =
  new : uriString:string -> Uri + 5 overloads
  member AbsolutePath : string
  member AbsoluteUri : string
  member Authority : string
  member DnsSafeHost : string
  member Equals : comparand:obj -> bool
  member Fragment : string
  member GetComponents : components:UriComponents * format:UriFormat -> string
  member GetHashCode : unit -> int
  member GetLeftPart : part:UriPartial -> string
  ...

--------------------
Uri(uriString: string) : 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>>)
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
NoteList.offset: int
NoteList.chunk: int
NoteList.total: int
type IDb =
  interface
    abstract member addUserNote : int -> string -> Async<Note>
    abstract member getUserNotes : int -> Async<NoteList>
  end
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
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>>
module Request

from Abstraction-monad.Suave
val text : string
val newNote : Note
val rvm : string
val msg : string
val BAD_REQUEST : s:string -> (Http.HttpContext -> OptionT<Async<Http.HttpContext option>>)
Multiple items
module WebPart

from Abstraction-monad.Suave

--------------------
type WebPart<'a> = 'a -> OptionT<Async<'a option>>
val path : s:string -> (Http.HttpContext -> OptionT<Async<Http.HttpContext option>>)