namespace System
namespace System.Net
val lookupName : id:int -> string option

Full name: Index.lookupName
val id : int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

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

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
union case Option.Some: Value: 'T -> Option<'T>
val lookupAge : id:int -> int option

Full name: Index.lookupAge
Multiple items
type MaybeBuilder =
  new : unit -> MaybeBuilder
  member Bind : input:'a option * f:('a -> 'b option) -> 'b option
  member Return : x:'c -> 'c option

Full name: Index.MaybeBuilder

--------------------
new : unit -> MaybeBuilder
val this : MaybeBuilder
member MaybeBuilder.Return : x:'c -> 'c option

Full name: Index.MaybeBuilder.Return
val x : 'c
member MaybeBuilder.Bind : input:'a option * f:('a -> 'b option) -> 'b option

Full name: Index.MaybeBuilder.Bind
val input : 'a option
val f : ('a -> 'b option)
union case Option.None: Option<'T>
val x : 'a
val maybe : MaybeBuilder

Full name: Index.maybe
val getCompleteDetails : id:int -> (string * int) option

Full name: Index.getCompleteDetails
val name : string
val age : int
val completeDetails : (string * int) option

Full name: Index.completeDetails
val seqResult : seq<int>

Full name: Index.seqResult
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
val fetchAsync : url:string -> Async<string>

Full name: Index.fetchAsync
val url : string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
Multiple items
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>
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 FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
static member Ignore : computation:Async<'T> -> Async<unit>
static member OnCancel : interruption:(unit -> unit) -> Async<IDisposable>
static member Parallel : computations:seq<Async<'T>> -> Async<'T []>
static member RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:CancellationToken -> 'T
static member Sleep : millisecondsDueTime:int -> Async<unit>
static member Start : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions * ?cancellationToken:CancellationToken -> Task<'T>
static member StartChild : computation:Async<'T> * ?millisecondsTimeout:int -> Async<Async<'T>>
static member StartChildAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions -> Async<Task<'T>>
static member StartImmediate : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartWithContinuations : computation:Async<'T> * continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) * ?cancellationToken:CancellationToken -> unit
static member SwitchToContext : syncContext:SynchronizationContext -> Async<unit>
static member SwitchToNewThread : unit -> Async<unit>
static member SwitchToThreadPool : unit -> Async<unit>
static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T>
static member CancellationToken : Async<CancellationToken>
static member DefaultCancellationToken : CancellationToken

Full name: Microsoft.FSharp.Control.Async

--------------------
type Async<'T>

Full name: Microsoft.FSharp.Control.Async<_>
val uri : System.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
  ...

Full name: System.Uri

--------------------
System.Uri(uriString: string) : unit
System.Uri(uriString: string, uriKind: System.UriKind) : unit
System.Uri(baseUri: System.Uri, relativeUri: System.Uri) : unit
System.Uri(baseUri: System.Uri, relativeUri: string) : unit
val webClient : WebClient
Multiple items
type WebClient =
  inherit Component
  new : unit -> WebClient
  member BaseAddress : string with get, set
  member CachePolicy : RequestCachePolicy with get, set
  member CancelAsync : unit -> unit
  member Credentials : ICredentials with get, set
  member DownloadData : address:string -> byte[] + 1 overload
  member DownloadDataAsync : address:Uri -> unit + 1 overload
  member DownloadDataTaskAsync : address:string -> Task<byte[]> + 1 overload
  member DownloadFile : address:string * fileName:string -> unit + 1 overload
  member DownloadFileAsync : address:Uri * fileName:string -> unit + 1 overload
  ...

Full name: System.Net.WebClient

--------------------
WebClient() : unit
member WebClient.AsyncDownloadString : address:System.Uri -> Async<string>
val readUriAsync : name:string * url:string -> Async<unit>

Full name: Index.readUriAsync
val async : AsyncBuilder

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
val html : string
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
property System.String.Length: int
val ex : exn
property System.Exception.Message: string
module MyOption

from index
Multiple items
module Option

from Microsoft.FSharp.Core

--------------------
type Option<'T> =
  | Some of 'T
  | None

Full name: index.MyOption.Option<_>
union case Option.Some: 'T -> Option<'T>
val getCompleteDetails2 : id:int -> (string * int) option

Full name: Index.getCompleteDetails2
member MaybeBuilder.Bind : input:'a option * f:('a -> 'b option) -> 'b option
member MaybeBuilder.Return : x:'c -> 'c option
type CExpr =
  | Yield of string
  | YieldFrom of string
  | Combine of CExpr * CExpr
  | Delay of CExpr
  | Bind of string * CExpr
  | Zero
  | Return of string
  | ReturnFrom of string
  | For of string * string
  | Run of CExpr
  ...

Full name: Index.CExpr
union case CExpr.Yield: string -> CExpr
union case CExpr.YieldFrom: string -> CExpr
union case CExpr.Combine: CExpr * CExpr -> CExpr
union case CExpr.Delay: CExpr -> CExpr
union case CExpr.Bind: string * CExpr -> CExpr
union case CExpr.Zero: CExpr
union case CExpr.Return: string -> CExpr
union case CExpr.ReturnFrom: string -> CExpr
union case CExpr.For: string * string -> CExpr
union case CExpr.Run: CExpr -> CExpr
union case CExpr.TryFinally: CExpr * string -> CExpr
union case CExpr.TryWith: CExpr * string -> CExpr
union case CExpr.Using: string * CExpr -> CExpr
union case CExpr.While: string * CExpr -> CExpr
Multiple items
type CEDebugBuilder =
  new : unit -> CEDebugBuilder
  member Bind : a:'h * f:(unit -> CExpr) -> CExpr
  member Combine : a:CExpr * b:CExpr -> CExpr
  member Delay : f:(unit -> CExpr) -> CExpr
  member For : s:'d * f:'e -> CExpr
  member Return : i:'g -> CExpr
  member ReturnFrom : i:'f -> CExpr
  member TryFinally : f:CExpr * e:'c -> CExpr
  member TryWith : expr:CExpr * handler:(Exception -> CExpr) -> CExpr
  member Using : v:'b * f:(unit -> CExpr) -> CExpr
  ...

Full name: Index.CEDebugBuilder

--------------------
new : unit -> CEDebugBuilder
val this : CEDebugBuilder
member CEDebugBuilder.Yield : i:'j -> CExpr

Full name: Index.CEDebugBuilder.Yield
val i : 'j
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
member CEDebugBuilder.YieldFrom : i:'i -> CExpr

Full name: Index.CEDebugBuilder.YieldFrom
val i : 'i
member CEDebugBuilder.Combine : a:CExpr * b:CExpr -> CExpr

Full name: Index.CEDebugBuilder.Combine
val a : CExpr
val b : CExpr
member CEDebugBuilder.Delay : f:(unit -> CExpr) -> CExpr

Full name: Index.CEDebugBuilder.Delay
val f : (unit -> CExpr)
member CEDebugBuilder.Bind : a:'h * f:(unit -> CExpr) -> CExpr

Full name: Index.CEDebugBuilder.Bind
val a : 'h
member CEDebugBuilder.Zero : unit -> CExpr

Full name: Index.CEDebugBuilder.Zero
member CEDebugBuilder.Return : i:'g -> CExpr

Full name: Index.CEDebugBuilder.Return
val i : 'g
member CEDebugBuilder.ReturnFrom : i:'f -> CExpr

Full name: Index.CEDebugBuilder.ReturnFrom
val i : 'f
member CEDebugBuilder.For : s:'d * f:'e -> CExpr

Full name: Index.CEDebugBuilder.For
val s : 'd
val f : 'e
member CEDebugBuilder.TryFinally : f:CExpr * e:'c -> CExpr

Full name: Index.CEDebugBuilder.TryFinally
val f : CExpr
val e : 'c
member CEDebugBuilder.TryWith : expr:CExpr * handler:(System.Exception -> CExpr) -> CExpr

Full name: Index.CEDebugBuilder.TryWith
val expr : CExpr
val handler : (System.Exception -> CExpr)
Multiple items
type Exception =
  new : unit -> Exception + 2 overloads
  member Data : IDictionary
  member GetBaseException : unit -> Exception
  member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
  member GetType : unit -> Type
  member HResult : int with get, set
  member HelpLink : string with get, set
  member InnerException : Exception
  member Message : string
  member Source : string with get, set
  ...

Full name: System.Exception

--------------------
System.Exception() : unit
System.Exception(message: string) : unit
System.Exception(message: string, innerException: exn) : unit
member CEDebugBuilder.Using : v:'b * f:(unit -> CExpr) -> CExpr

Full name: Index.CEDebugBuilder.Using
val v : 'b
member CEDebugBuilder.While : v:(unit -> 'a) * f:CExpr -> CExpr

Full name: Index.CEDebugBuilder.While
val v : (unit -> 'a)
val bar : CEDebugBuilder

Full name: Index.bar
Multiple items
type CEDebugBuilderNoDelay =
  new : unit -> CEDebugBuilderNoDelay
  member Bind : a:'h * f:(unit -> CExpr) -> CExpr
  member Combine : a:CExpr * b:CExpr -> CExpr
  member For : s:'d * f:'e -> CExpr
  member Return : i:'g -> CExpr
  member ReturnFrom : i:'f -> CExpr
  member TryFinally : f:CExpr * e:'c -> CExpr
  member TryWith : expr:CExpr * handler:(Exception -> CExpr) -> CExpr
  member Using : v:'b * f:(unit -> CExpr) -> CExpr
  member While : v:(unit -> 'a) * f:CExpr -> CExpr
  ...

Full name: Index.CEDebugBuilderNoDelay

--------------------
new : unit -> CEDebugBuilderNoDelay
val this : CEDebugBuilderNoDelay
member CEDebugBuilderNoDelay.Yield : i:'j -> CExpr

Full name: Index.CEDebugBuilderNoDelay.Yield
member CEDebugBuilderNoDelay.YieldFrom : i:'i -> CExpr

Full name: Index.CEDebugBuilderNoDelay.YieldFrom
member CEDebugBuilderNoDelay.Combine : a:CExpr * b:CExpr -> CExpr

Full name: Index.CEDebugBuilderNoDelay.Combine
member CEDebugBuilderNoDelay.Bind : a:'h * f:(unit -> CExpr) -> CExpr

Full name: Index.CEDebugBuilderNoDelay.Bind
member CEDebugBuilderNoDelay.Zero : unit -> CExpr

Full name: Index.CEDebugBuilderNoDelay.Zero
member CEDebugBuilderNoDelay.Return : i:'g -> CExpr

Full name: Index.CEDebugBuilderNoDelay.Return
member CEDebugBuilderNoDelay.ReturnFrom : i:'f -> CExpr

Full name: Index.CEDebugBuilderNoDelay.ReturnFrom
member CEDebugBuilderNoDelay.For : s:'d * f:'e -> CExpr

Full name: Index.CEDebugBuilderNoDelay.For
member CEDebugBuilderNoDelay.TryFinally : f:CExpr * e:'c -> CExpr

Full name: Index.CEDebugBuilderNoDelay.TryFinally
member CEDebugBuilderNoDelay.TryWith : expr:CExpr * handler:(System.Exception -> CExpr) -> CExpr

Full name: Index.CEDebugBuilderNoDelay.TryWith
member CEDebugBuilderNoDelay.Using : v:'b * f:(unit -> CExpr) -> CExpr

Full name: Index.CEDebugBuilderNoDelay.Using
member CEDebugBuilderNoDelay.While : v:(unit -> 'a) * f:CExpr -> CExpr

Full name: Index.CEDebugBuilderNoDelay.While
val foo : CEDebugBuilderNoDelay

Full name: Index.foo
member CEDebugBuilderNoDelay.Yield : i:'j -> CExpr
member CEDebugBuilderNoDelay.YieldFrom : i:'i -> CExpr
member CEDebugBuilderNoDelay.Return : i:'g -> CExpr
member CEDebugBuilderNoDelay.ReturnFrom : i:'f -> CExpr
member CEDebugBuilderNoDelay.Zero : unit -> CExpr
val a : unit
member CEDebugBuilderNoDelay.Using : v:'b * f:(unit -> CExpr) -> CExpr
member CEDebugBuilderNoDelay.Bind : a:'h * f:(unit -> CExpr) -> CExpr
val printf : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printf
member CEDebugBuilder.Delay : f:(unit -> CExpr) -> CExpr
member CEDebugBuilder.Combine : a:CExpr * b:CExpr -> CExpr
member CEDebugBuilder.Return : i:'g -> CExpr
val x : obj
member CEDebugBuilder.For : s:'d * f:'e -> CExpr
member CEDebugBuilder.While : v:(unit -> 'a) * f:CExpr -> CExpr
member CEDebugBuilder.TryFinally : f:CExpr * e:'c -> CExpr
Multiple items
type DivideByZeroException =
  inherit ArithmeticException
  new : unit -> DivideByZeroException + 2 overloads

Full name: System.DivideByZeroException

--------------------
System.DivideByZeroException() : unit
System.DivideByZeroException(message: string) : unit
System.DivideByZeroException(message: string, innerException: exn) : unit
val e : System.DivideByZeroException
member CEDebugBuilder.TryWith : expr:CExpr * handler:(System.Exception -> CExpr) -> CExpr
val e : System.Exception
Multiple items
val exn : System.Exception

--------------------
type exn = System.Exception

Full name: Microsoft.FSharp.Core.exn
val reraise : unit -> 'T

Full name: Microsoft.FSharp.Core.Operators.reraise
val getPage : n:int -> Async<seq<int>>

Full name: Index.getPage
val n : int
val raise : exn:System.Exception -> 'T

Full name: Microsoft.FSharp.Core.Operators.raise
Multiple items
type NotImplementedException =
  inherit SystemException
  new : unit -> NotImplementedException + 2 overloads

Full name: System.NotImplementedException

--------------------
System.NotImplementedException() : unit
System.NotImplementedException(message: string) : unit
System.NotImplementedException(message: string, inner: exn) : unit
val getPage : n:int -> Async<seq<int>>

Full name: index.MyOption.getPage
val getAllPagesSeq : seq<int>

Full name: Index.getAllPagesSeq
val loop : (int -> seq<int>)
val results : seq<int>
static member Async.RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:System.Threading.CancellationToken -> 'T
module Seq

from Microsoft.FSharp.Collections
val empty<'T> : seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.empty
val getAllPagesAsync : Async<seq<int>>

Full name: Index.getAllPagesAsync
val loop : (int -> seq<int> -> Async<seq<int>>)
val acc : seq<int>
val append : source1:seq<'T> -> source2:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.append
type AsyncSeq<'T> = Async<AsyncSeqInner<'T>>

Full name: Index.AsyncSeq<_>
type AsyncSeqInner<'T> =
  internal | Nil
           | Cons of 'T * AsyncSeq<'T>

Full name: Index.AsyncSeqInner<_>
union case AsyncSeqInner.Nil: AsyncSeqInner<'T>
union case AsyncSeqInner.Cons: 'T * AsyncSeq<'T> -> AsyncSeqInner<'T>
Multiple items
type GeneralizableValueAttribute =
  inherit Attribute
  new : unit -> GeneralizableValueAttribute

Full name: Microsoft.FSharp.Core.GeneralizableValueAttribute

--------------------
new : unit -> GeneralizableValueAttribute
val empty<'T> : AsyncSeq<'T>

Full name: Index.empty
val singleton : v:'T -> AsyncSeq<'T>

Full name: Index.singleton
val v : 'T
val append : seq1:AsyncSeq<'T> -> seq2:AsyncSeq<'T> -> AsyncSeq<'T>

Full name: Index.append
val seq1 : AsyncSeq<'T>
val seq2 : AsyncSeq<'T>
val v1 : AsyncSeqInner<'T>
val h : 'T
val t : AsyncSeq<'T>
val toAsyncSeq : xs:seq<'a> -> AsyncSeq<'a>

Full name: Index.toAsyncSeq
val xs : seq<'a>
val head : source:seq<'T> -> 'T

Full name: Microsoft.FSharp.Collections.Seq.head
val skip : count:int -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.skip
Multiple items
type AsyncSeqBuilder =
  new : unit -> AsyncSeqBuilder
  member Bind : inp:Async<'b> * body:('b -> Async<'c>) -> Async<'c>
  member Combine : seq1:AsyncSeq<'d> * seq2:AsyncSeq<'d> -> AsyncSeq<'d>
  member Delay : f:(unit -> AsyncSeq<'T>) -> Async<AsyncSeqInner<'T>>
  member For : seq:seq<'T> * action:('T -> AsyncSeq<'TResult>) -> Async<AsyncSeqInner<'TResult>>
  member For : seq:AsyncSeq<'T> * action:('T -> AsyncSeq<'TResult>) -> AsyncSeq<'TResult>
  member TryFinally : body:AsyncSeq<'T> * compensation:(unit -> unit) -> Async<AsyncSeqInner<'T>>
  member While : gd:(unit -> bool) * seq:AsyncSeq<'T> -> AsyncSeq<'T>
  member Yield : v:'e -> AsyncSeq<'e>
  member YieldFrom : s:seq<'a> -> AsyncSeq<'a>
  ...

Full name: Index.AsyncSeqBuilder

--------------------
new : unit -> AsyncSeqBuilder
val x : AsyncSeqBuilder
member AsyncSeqBuilder.Yield : v:'e -> AsyncSeq<'e>

Full name: Index.AsyncSeqBuilder.Yield
val v : 'e
member AsyncSeqBuilder.YieldFrom : s:seq<'a> -> AsyncSeq<'a>

Full name: Index.AsyncSeqBuilder.YieldFrom
val s : seq<'a>
member AsyncSeqBuilder.YieldFrom : s:AsyncSeq<'a> -> AsyncSeq<'a>

Full name: Index.AsyncSeqBuilder.YieldFrom
val s : AsyncSeq<'a>
member AsyncSeqBuilder.Combine : seq1:AsyncSeq<'d> * seq2:AsyncSeq<'d> -> AsyncSeq<'d>

Full name: Index.AsyncSeqBuilder.Combine
val seq1 : AsyncSeq<'d>
val seq2 : AsyncSeq<'d>
member AsyncSeqBuilder.Bind : inp:Async<'b> * body:('b -> Async<'c>) -> Async<'c>

Full name: Index.AsyncSeqBuilder.Bind
val inp : Async<'b>
val body : ('b -> Async<'c>)
member AsyncBuilder.Bind : computation:Async<'T> * binder:('T -> Async<'U>) -> Async<'U>
member AsyncSeqBuilder.Delay : f:(unit -> AsyncSeq<'T>) -> Async<AsyncSeqInner<'T>>

Full name: Index.AsyncSeqBuilder.Delay
val f : (unit -> AsyncSeq<'T>)
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
member AsyncBuilder.Delay : generator:(unit -> Async<'T>) -> Async<'T>
member AsyncSeqBuilder.Zero : unit -> AsyncSeq<'a>

Full name: Index.AsyncSeqBuilder.Zero
val asyncSeq : AsyncSeqBuilder

Full name: Index.asyncSeq
val internal tryNext : input:AsyncSeq<'a> -> Async<Choice<AsyncSeqInner<'a>,exn>>

Full name: Index.tryNext


 Tries to get the next element of an asynchronous sequence
 and returns either the value or an exception
val input : AsyncSeq<'a>
val v : AsyncSeqInner<'a>
union case Choice.Choice1Of2: 'T1 -> Choice<'T1,'T2>
val e : exn
union case Choice.Choice2Of2: 'T2 -> Choice<'T1,'T2>
val internal tryFinally : input:AsyncSeq<'T> -> compensation:(unit -> unit) -> Async<AsyncSeqInner<'T>>

Full name: Index.tryFinally


 Implements the 'TryFinally' functionality for computation builder
val input : AsyncSeq<'T>
val compensation : (unit -> unit)
val v : Choice<AsyncSeqInner<'T>,exn>
val collect : f:('T -> AsyncSeq<'TResult>) -> input:AsyncSeq<'T> -> AsyncSeq<'TResult>

Full name: Index.collect
val f : ('T -> AsyncSeq<'TResult>)
val v : AsyncSeqInner<'T>
member AsyncSeqBuilder.While : gd:(unit -> bool) * seq:AsyncSeq<'T> -> AsyncSeq<'T>

Full name: Index.AsyncSeqBuilder.While
val gd : (unit -> bool)
Multiple items
val seq : AsyncSeq<'T>

--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
member AsyncSeqBuilder.Combine : seq1:AsyncSeq<'d> * seq2:AsyncSeq<'d> -> AsyncSeq<'d>
member AsyncSeqBuilder.Delay : f:(unit -> AsyncSeq<'T>) -> Async<AsyncSeqInner<'T>>
member AsyncSeqBuilder.While : gd:(unit -> bool) * seq:AsyncSeq<'T> -> AsyncSeq<'T>
member AsyncSeqBuilder.Zero : unit -> AsyncSeq<'a>
member AsyncSeqBuilder.TryFinally : body:AsyncSeq<'T> * compensation:(unit -> unit) -> Async<AsyncSeqInner<'T>>

Full name: Index.AsyncSeqBuilder.TryFinally
val body : AsyncSeq<'T>
member AsyncSeqBuilder.For : seq:seq<'T> * action:('T -> AsyncSeq<'TResult>) -> Async<AsyncSeqInner<'TResult>>

Full name: Index.AsyncSeqBuilder.For
Multiple items
val seq : seq<'T>

--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
val action : ('T -> AsyncSeq<'TResult>)
val enum : System.Collections.Generic.IEnumerator<'T>
System.Collections.Generic.IEnumerable.GetEnumerator() : System.Collections.Generic.IEnumerator<'T>
member AsyncSeqBuilder.TryFinally : body:AsyncSeq<'T> * compensation:(unit -> unit) -> Async<AsyncSeqInner<'T>>
System.Collections.IEnumerator.MoveNext() : bool
property System.Collections.Generic.IEnumerator.Current: 'T
System.IDisposable.Dispose() : unit
member AsyncSeqBuilder.For : seq:AsyncSeq<'T> * action:('T -> AsyncSeq<'TResult>) -> AsyncSeq<'TResult>

Full name: Index.AsyncSeqBuilder.For
val resultLoop : n:int -> Async<AsyncSeqInner<int>>

Full name: Index.resultLoop
val getAllResults : Async<AsyncSeqInner<int>>

Full name: Index.getAllResults
val withPageNumber : Async<AsyncSeqInner<string>>

Full name: Index.withPageNumber
val result : int
val filterAsync : f:('T -> Async<bool>) -> input:AsyncSeq<'T> -> Async<AsyncSeqInner<'T>>

Full name: Index.filterAsync
val f : ('T -> Async<bool>)
val b : bool
type WriteResult =
  | WriteSuccess
  | WrongExpectedVersion
  | WriteError of Exception

Full name: Index.WriteResult
union case WriteResult.WriteSuccess: WriteResult
union case WriteResult.WrongExpectedVersion: WriteResult
union case WriteResult.WriteError: System.Exception -> WriteResult
type Key = string

Full name: Index.Key
type Version = int

Full name: Index.Version
type KeyValueLanguage<'N> =
  | ReadValue of Key * ((Version * string) option -> 'N)
  | WriteValue of Key * Version * string * (WriteResult -> 'N)

Full name: Index.KeyValueLanguage<_>
union case KeyValueLanguage.ReadValue: Key * ((Version * string) option -> 'N) -> KeyValueLanguage<'N>
type 'T option = Option<'T>

Full name: Microsoft.FSharp.Core.option<_>
union case KeyValueLanguage.WriteValue: Key * Version * string * (WriteResult -> 'N) -> KeyValueLanguage<'N>
type FreeKeyValue<'F,'R> =
  | FreeKeyValue of KeyValueLanguage<FreeKeyValue<'F,'R>>
  | Pure of 'R

Full name: Index.FreeKeyValue<_,_>
Multiple items
union case FreeKeyValue.FreeKeyValue: KeyValueLanguage<FreeKeyValue<'F,'R>> -> FreeKeyValue<'F,'R>

--------------------
type FreeKeyValue<'F,'R> =
  | FreeKeyValue of KeyValueLanguage<FreeKeyValue<'F,'R>>
  | Pure of 'R

Full name: Index.FreeKeyValue<_,_>
union case FreeKeyValue.Pure: 'R -> FreeKeyValue<'F,'R>
val fmap : f:('a -> 'b) -> streamWorker:KeyValueLanguage<'a> -> KeyValueLanguage<'b>

Full name: Index.fmap
val f : ('a -> 'b)
val streamWorker : KeyValueLanguage<'a>
val key : Key
val streamRead : ((Version * string) option -> 'a)
val expectedVersion : Version
val value : string
val next : (WriteResult -> 'a)
val bind' : f:('a -> FreeKeyValue<'b,'c>) -> v:FreeKeyValue<'d,'a> -> FreeKeyValue<'b,'c>

Full name: Index.bind'
val f : ('a -> FreeKeyValue<'b,'c>)
val v : FreeKeyValue<'d,'a>
val x : KeyValueLanguage<FreeKeyValue<'d,'a>>
val r : 'a
val result : value:'a -> FreeKeyValue<'b,'a>

Full name: Index.result
val value : 'a
val whileLoop : pred:(unit -> bool) -> body:FreeKeyValue<'a,'b> -> FreeKeyValue<'c,unit>

Full name: Index.whileLoop
val pred : (unit -> bool)
val body : FreeKeyValue<'a,'b>
val delay : func:(unit -> FreeKeyValue<'a,'b>) -> FreeKeyValue<'a,'b>

Full name: Index.delay
val func : (unit -> FreeKeyValue<'a,'b>)
val combine : expr1:FreeKeyValue<'a,unit> -> expr2:FreeKeyValue<'b,'c> -> FreeKeyValue<'b,'c>

Full name: Index.combine
val expr1 : FreeKeyValue<'a,unit>
val expr2 : FreeKeyValue<'b,'c>
val forLoop : collection:seq<'a> -> func:('a -> FreeKeyValue<'b,'c>) -> FreeKeyValue<'d,unit>

Full name: Index.forLoop
val collection : seq<'a>
val func : ('a -> FreeKeyValue<'b,'c>)
val ie : System.Collections.Generic.IEnumerator<'a>
System.Collections.Generic.IEnumerable.GetEnumerator() : System.Collections.Generic.IEnumerator<'a>
property System.Collections.Generic.IEnumerator.Current: 'a
val readValue : key:Key -> FreeKeyValue<'a,(Version * string) option>

Full name: Index.readValue
val writeValue : key:Key -> version:Version -> value:string -> FreeKeyValue<'a,WriteResult>

Full name: Index.writeValue
val version : Version
type InterpeterState<'T> =
  | Continue of (Map<string,(int * string)> * FreeKeyValue<obj,'T>)
  | Complete of (Map<string,(int * string)> * 'T)

Full name: Index.InterpeterState<_>
union case InterpeterState.Continue: (Map<string,(int * string)> * FreeKeyValue<obj,'T>) -> InterpeterState<'T>
Multiple items
module Map

from Microsoft.FSharp.Collections

--------------------
type Map<'Key,'Value (requires comparison)> =
  interface IEnumerable
  interface IComparable
  interface IEnumerable<KeyValuePair<'Key,'Value>>
  interface ICollection<KeyValuePair<'Key,'Value>>
  interface IDictionary<'Key,'Value>
  new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
  member Add : key:'Key * value:'Value -> Map<'Key,'Value>
  member ContainsKey : key:'Key -> bool
  override Equals : obj -> bool
  member Remove : key:'Key -> Map<'Key,'Value>
  ...

Full name: Microsoft.FSharp.Collections.Map<_,_>

--------------------
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
type obj = System.Object

Full name: Microsoft.FSharp.Core.obj
union case InterpeterState.Complete: (Map<string,(int * string)> * 'T) -> InterpeterState<'T>
val runStep : prog:FreeKeyValue<obj,'T> -> dataStore:Map<Key,(Version * string)> -> InterpeterState<'T>

Full name: Index.runStep
val prog : FreeKeyValue<obj,'T>
val dataStore : Map<Key,(Version * string)>
val f : ((Version * string) option -> FreeKeyValue<obj,'T>)
val value : (Version * string) option
val tryFind : key:'Key -> table:Map<'Key,'T> -> 'T option (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.tryFind
val next : FreeKeyValue<obj,'T>
val f : (WriteResult -> FreeKeyValue<obj,'T>)
val currentValue : (Version * string) option
val dataStore' : Map<Key,(Version * string)>
val add : key:'Key -> value:'T -> table:Map<'Key,'T> -> Map<'Key,'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.add
val currentVersion : Version
val result : 'T
val interpret : prog:FreeKeyValue<obj,'T> -> dataStore:Map<Key,(Version * string)> -> Map<Key,(Version * string)> * 'T

Full name: Index.interpret
val loop : (InterpeterState<'T> -> Map<string,(int * string)> * 'T)
val state : InterpeterState<'T>
val r : Map<string,(int * string)> * 'T
val state : Map<string,(int * string)>
val p : FreeKeyValue<obj,'T>
Multiple items
type KeyValueBuilder =
  new : unit -> KeyValueBuilder
  member Bind : inp:FreeKeyValue<'m,'n> * body:('n -> FreeKeyValue<'o,'p>) -> FreeKeyValue<'o,'p>
  member Combine : expr1:FreeKeyValue<'j,unit> * expr2:FreeKeyValue<'k,'l> -> FreeKeyValue<'k,'l>
  member Delay : func:(unit -> FreeKeyValue<'a,'b>) -> FreeKeyValue<'a,'b>
  member For : a:seq<'f> * f:('f -> FreeKeyValue<'g,'h>) -> FreeKeyValue<'i,unit>
  member Return : r:'R -> FreeKeyValue<'F,'R>
  member ReturnFrom : r:FreeKeyValue<'F,'R> -> FreeKeyValue<'F,'R>
  member While : func:(unit -> bool) * body:FreeKeyValue<'c,'d> -> FreeKeyValue<'e,unit>
  member Zero : unit -> FreeKeyValue<'q,unit>

Full name: Index.KeyValueBuilder

--------------------
new : unit -> KeyValueBuilder
val x : KeyValueBuilder
member KeyValueBuilder.Zero : unit -> FreeKeyValue<'q,unit>

Full name: Index.KeyValueBuilder.Zero
member KeyValueBuilder.Return : r:'R -> FreeKeyValue<'F,'R>

Full name: Index.KeyValueBuilder.Return
val r : 'R
member KeyValueBuilder.ReturnFrom : r:FreeKeyValue<'F,'R> -> FreeKeyValue<'F,'R>

Full name: Index.KeyValueBuilder.ReturnFrom
val r : FreeKeyValue<'F,'R>
member KeyValueBuilder.Bind : inp:FreeKeyValue<'m,'n> * body:('n -> FreeKeyValue<'o,'p>) -> FreeKeyValue<'o,'p>

Full name: Index.KeyValueBuilder.Bind
val inp : FreeKeyValue<'m,'n>
val body : ('n -> FreeKeyValue<'o,'p>)
member KeyValueBuilder.Combine : expr1:FreeKeyValue<'j,unit> * expr2:FreeKeyValue<'k,'l> -> FreeKeyValue<'k,'l>

Full name: Index.KeyValueBuilder.Combine
val expr1 : FreeKeyValue<'j,unit>
val expr2 : FreeKeyValue<'k,'l>
member KeyValueBuilder.For : a:seq<'f> * f:('f -> FreeKeyValue<'g,'h>) -> FreeKeyValue<'i,unit>

Full name: Index.KeyValueBuilder.For
val a : seq<'f>
val f : ('f -> FreeKeyValue<'g,'h>)
member KeyValueBuilder.While : func:(unit -> bool) * body:FreeKeyValue<'c,'d> -> FreeKeyValue<'e,unit>

Full name: Index.KeyValueBuilder.While
val func : (unit -> bool)
val body : FreeKeyValue<'c,'d>
member KeyValueBuilder.Delay : func:(unit -> FreeKeyValue<'a,'b>) -> FreeKeyValue<'a,'b>

Full name: Index.KeyValueBuilder.Delay
val keyValue : KeyValueBuilder

Full name: Index.keyValue
val appendValue : key:Key -> value:string -> FreeKeyValue<'a,WriteResult>

Full name: Index.appendValue
val current : (Version * string) option
val currentValue : string
val newValue : string
val result : WriteResult
val appendResult : Map<Key,(Version * string)> * WriteResult

Full name: Index.appendResult
val empty<'Key,'T (requires comparison)> : Map<'Key,'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.empty
val appendValueWithRetry : key:Key -> value:string -> FreeKeyValue<'a,WriteResult>

Full name: Index.appendValueWithRetry
val loop : (WriteResult -> FreeKeyValue<'b,WriteResult>)
val previousResult : WriteResult
type IRealDataStore =
  interface
    abstract member Read : Key -> Async<(Version * string) option>
    abstract member Write : Key -> Version -> string -> Async<WriteResult>
  end

Full name: Index.IRealDataStore
abstract member IRealDataStore.Read : Key -> Async<(Version * string) option>

Full name: Index.IRealDataStore.Read
abstract member IRealDataStore.Write : Key -> Version -> string -> Async<WriteResult>

Full name: Index.IRealDataStore.Write
val realInterpreter : prog:FreeKeyValue<obj,'T> -> realDataStore:IRealDataStore -> Async<'T>

Full name: Index.realInterpreter
val realDataStore : IRealDataStore
abstract member IRealDataStore.Read : Key -> Async<(Version * string) option>
abstract member IRealDataStore.Write : Key -> Version -> string -> Async<WriteResult>
val interpret2 : prog1:FreeKeyValue<obj,'T> -> prog2:FreeKeyValue<obj,'T> -> dataStore:Map<Key,(Version * string)> -> Map<Key,(Version * string)> * 'T * 'T

Full name: Index.interpret2
val prog1 : FreeKeyValue<obj,'T>
val prog2 : FreeKeyValue<obj,'T>
val runOne : (FreeKeyValue<obj,'a> -> 'b -> Map<Key,(Version * string)> -> 'b * FreeKeyValue<obj,'a> * Map<string,(int * string)>)
val pRun : FreeKeyValue<obj,'a>
val pOther : 'b
val ds : Map<Key,(Version * string)>
val ds' : Map<string,(int * string)>
val pRun' : FreeKeyValue<obj,'a>
val a : 'a
val loop : (FreeKeyValue<obj,'a> * FreeKeyValue<obj,'a> * Map<string,(int * string)> -> Map<string,(int * string)> * 'a * 'a)
val p1 : FreeKeyValue<obj,'a>
val p2 : FreeKeyValue<obj,'a>
val ds : Map<string,(int * string)>
val r1 : 'a
val r2 : 'a
val appendResult2 : Map<Key,(Version * string)> * WriteResult * WriteResult

Full name: Index.appendResult2

Lets see what we can do! with F# Computation Expressions

By Andrew Browne

Seq

1: 
2: 
3: 
4: 
5: 
6: 
7: 
let seqResult = seq {
    yield 1
    yield! seq {
        yield 2
        yield 3
    }
}
seq [1; 2; 3]

Async

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
let readUriAsync(name, url:string) = async { 
    try 
        let! html = fetchAsync url
        printfn 
           "Read %d characters for %s" 
           html.Length 
           name
    with
        | ex -> printfn "%s" (ex.Message);
}

Option

1: 
2: 
3: 
4: 
module MyOption = 
type Option<'T> =
| Some of 'T
| None

Maybe

1: 
2: 
3: 
4: 
5: 
let getCompleteDetails id = maybe {
  let! name = lookupName id
  let! age = lookupAge id
  return (name, age)
}
Some ("Andrew", 32)

Maybe Desugared

1: 
2: 
3: 
4: 
5: 
let getCompleteDetails2 id = 
       maybe.Bind(lookupName id, (fun name ->
          maybe.Bind(lookupAge id, (fun age ->
            maybe.Return((name,age)
       )))))

Maybe Builder

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
type MaybeBuilder() = 
  member this.Return(x) = Some x

  member this.Bind(input, f) =
      match input with 
      | None -> None 
      | Some x -> f x 

let maybe = MaybeBuilder()

Transformations: yield

1: 
2: 
3: 
foo {
    yield 1
}
1: 
foo.Yield(1)

Transformations: yield!

1: 
2: 
3: 
foo {
    yield! 1
}
1: 
foo.YieldFrom(1)

Transformations: return

1: 
2: 
3: 
foo {
    return 1
}
1: 
foo.Return(1)

Transformations: return!

1: 
2: 
3: 
foo {
    return! 1
}
1: 
foo.ReturnFrom(1)

Transformations: if else

1: 
2: 
3: 
4: 
5: 
6: 
foo {
    if true then
       return 1
    else
       return 2
}
1: 
2: 
3: 
4: 
if true then
   foo.Return(1)
else
   foo.Return(2)

Transformations: if

1: 
2: 
3: 
4: 
foo {
    if true then
       return 1
}
1: 
2: 
3: 
4: 
if false then
   foo.Return(1)
else
   foo.Zero()

Transformations: use

1: 
2: 
3: 
4: 
foo {
    use a = 1
    return a
}
1: 
foo.Using(1, fun a -> foo.Return(a))

Transformations: use!

1: 
2: 
3: 
4: 
foo {
    use! a = 1
    return a
}
1: 
2: 
3: 
4: 
5: 
foo.Bind(
  1, 
  fun a -> 
    foo.Using(a, 
      fun a -> foo.Return(a)))

Transformations: do!

1: 
2: 
3: 
4: 
foo {
    do! printf "1"
    return 2
}
1: 
2: 
3: 
foo.Bind(
  "1",
  fun () -> foo.Return(2))

Transformations: combine

1: 
2: 
3: 
4: 
bar {
    return "1"
    return "2"
}
1: 
2: 
3: 
4: 
bar.Delay(fun () ->
    bar.Combine(
        bar.Return("1"), 
        bar.Delay(fun () -> bar.Return("2"))))

Transformations: For

1: 
2: 
3: 
4: 
bar {
    for x in [1..3] do
        return x
}
1: 
2: 
3: 
4: 
bar.Delay(fun () ->
    bar.For(
        [1..3],
        fun x -> bar.Return(x)))

Transformations: While

1: 
2: 
3: 
4: 
bar {
    while true do
       return "1"
}
1: 
2: 
3: 
4: 
bar.Delay(fun () ->
    bar.While(
        (fun () -> true),
        bar.Delay(fun () -> bar.Return("1"))))

Transformations: Try Finally

1: 
2: 
3: 
4: 
5: 
6: 
bar {
    try
       return "value"
    finally
       printfn "finally"
}
1: 
2: 
3: 
4: 
bar.Delay(fun () ->
    bar.TryFinally(
        bar.Delay(fun () -> bar.Return("value")), 
        fun () -> printfn "finally"))

Transformations: Try With

1: 
2: 
3: 
4: 
5: 
6: 
bar {
    try
       return 1 / 0
    with | :? System.DivideByZeroException as e ->
       return 0
}
1: 
2: 
3: 
4: 
5: 
6: 
7: 
bar.TryWith(
    bar.Delay(fun () -> bar.Return(1/0)), 
    (fun e -> 
        match e with 
        | :? System.DivideByZeroException as e -> 
            bar.Return(0)
        | exn -> reraise() ))

Async Seq Paging

http://tomasp.net/blog/async-sequences.aspx/

1: 
let getPage (n : int) : Async<seq<int>>

Async Seq Paging

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
let getAllPagesSeq : seq<int> = 
  let rec loop n = seq {
      let results = 
          getPage n 
          |> Async.RunSynchronously
      yield! results
      if results <> Seq.empty then
          yield! loop (n + 1)
  }
  loop 0

Async Seq Paging

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
let getAllPagesAsync : Async<seq<int>> = 
  let rec loop n acc = async {
      let! results = getPage n 
      if results <> Seq.empty then
          return! 
              loop (n + 1) 
                   (Seq.append acc results)
      else
          return acc
  }
  loop 0 Seq.empty

AsyncSeq

1: 
2: 
3: 
4: 
5: 
type AsyncSeq<'T> = Async<AsyncSeqInner<'T>> 
and AsyncSeqInner<'T> = 
    internal
    | Nil
    | Cons of 'T * AsyncSeq<'T>

Async Seq Builder

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
type AsyncSeqBuilder() =
    member x.Yield(v) = singleton v
    member x.YieldFrom (s : seq<'a>) = toAsyncSeq s
    member x.YieldFrom (s : AsyncSeq<'a>) = s
    member x.Combine (seq1,seq2) = 
      append seq1 seq2
    member x.Bind (inp, body) = 
      async.Bind(inp, body)
    member x.Delay (f:unit -> AsyncSeq<'T>) = 
      async.Delay(f)
    member x.Zero () = empty
    

Async Seq Paging

1: 
2: 
3: 
4: 
5: 
6: 
7: 
let rec resultLoop n = asyncSeq {
  let! results = getPage n
  yield! results
  if results <> Seq.empty then
    yield! resultLoop (n + 1)
}
let getAllResults = resultLoop 0

Async Seq Paging

1: 
2: 
3: 
4: 
let withPageNumber = asyncSeq {
  for result in getAllResults do
    yield sprintf "Item: %d" result
}

Async Seq Paging

1: 
2: 
3: 
4: 
5: 
let filterAsync f (input : AsyncSeq<'T>) = 
  asyncSeq {
      for v in input do
        let! b = f v
        if b then yield v }

A Simple DSL

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
let appendValue key value = keyValue {
     let! current = readValue key
     match current with
     | Some (version, currentValue) -> 
         let newValue = currentValue + value
         let! result = 
             writeValue key (version + 1) newValue
         return result
     | None ->
         let! result = writeValue key 0 value
         return result
   }

A Simple DSL

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
type KeyValueLanguage<'N> =
    | ReadValue of 
        Key * ((Version * string) option -> 'N)
    | WriteValue of 
        Key * Version * string * (WriteResult -> 'N)
and 
    FreeKeyValue<'F,'R> = 
    | FreeKeyValue of  
       KeyValueLanguage<FreeKeyValue<'F,'R>>
    | Pure of 'R

DSL Functions

1: 
2: 
3: 
4: 
let readValue key = 
    FreeKeyValue (ReadValue (key, Pure))
let writeValue key version value = 
    FreeKeyValue (WriteValue (key, version, value, Pure))

DSL Interpreter

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
let runStep 
    (prog : FreeKeyValue<obj,'T>)
    (dataStore : Map<Key,(Version * string)>) 
    : InterpeterState<'T> =
    match prog with
    | FreeKeyValue (ReadValue (key, f)) ->
        let value = Map.tryFind key dataStore
        let next = f value
        Continue (dataStore, next)
    | FreeKeyValue (WriteValue (key, version, value, f)) ->
        let currentValue = Map.tryFind key dataStore
        match currentValue with
        | None when version = 0 ->
           let dataStore' = Map.add key (version, value) dataStore
           Continue (dataStore', f WriteSuccess)
        | Some (currentVersion, _) when currentVersion + 1 = version -> 
           let dataStore' = Map.add key (version, value) dataStore
           Continue (dataStore', f WriteSuccess)
        | _ -> 
           Continue (dataStore, f WrongExpectedVersion)
    | Pure result ->
        Complete (dataStore,result)

DSL Interpreter

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
let interpret
    (prog : FreeKeyValue<obj,'T>)
    (dataStore : Map<Key,(Version * string)>) 
    : (Map<Key,(Version * string)> * 'T) =
    let rec loop 
       (state: InterpeterState<'T>) =
       match state with
       | Complete r -> r
       | Continue (state, p) ->
          loop <| runStep p state

    loop (Continue (dataStore, prog))

DSL Builder

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
type KeyValueBuilder() =
    member x.Zero() = Pure ()
    member x.Return(r:'R) : FreeKeyValue<'F,'R> = Pure r
    member x.ReturnFrom(r:FreeKeyValue<'F,'R>) = r
    member x.Bind (inp, body) = bind' body inp
    member x.Combine(expr1, expr2) = combine expr1 expr2
    member x.For(a, f) = forLoop a f 
    member x.While(func, body) = whileLoop func body
    member x.Delay(func) = delay func

let keyValue = new KeyValueBuilder()

KeyValue bind

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
let fmap f streamWorker = 
    match streamWorker with
    | ReadValue (key, streamRead) -> 
        ReadValue (key, (streamRead >> f))
    | WriteValue (key, expectedVersion, value, next) -> 
        WriteValue (key, expectedVersion, value, (next >> f))

let rec bind' f v =
    match v with
    | FreeKeyValue x -> FreeKeyValue (fmap (bind' f) x)
    | Pure r -> f r

DSL example

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
let appendValue key value = keyValue {
     let! current = readValue key
     match current with
     | Some (version, currentValue) -> 
         let newValue = currentValue + value
         let! result = 
             writeValue key (version + 1) newValue
         return result
     | None ->
         let! result = writeValue key 0 value
         return result
   }
1: 
let appendResult = interpret (appendValue "key" "abcd") Map.empty
(map [("key", (0, "abcd"))], WriteSuccess)

DSL example

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
let appendValueWithRetry key value = 
   let rec loop previousResult = keyValue {
     match previousResult with
     | WrongExpectedVersion -> 
        return! (appendValue key value)
     | _ ->
        return previousResult
   }

   loop WrongExpectedVersion

Real DSL Interpreter

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
let rec realInterpreter 
    (prog : FreeKeyValue<obj,'T>)
    (realDataStore : IRealDataStore) 
    : Async<'T> =
    match prog with
    | FreeKeyValue (ReadValue (key, f)) -> async {
        let! value = realDataStore.Read key
        return! realInterpreter (f value) realDataStore }
    | FreeKeyValue (WriteValue (key, version, value, f)) -> async {
        let! result = realDataStore.Write key version value
        return! realInterpreter (f result) realDataStore }
    | Pure result ->
        async { return result }

DSL Interpreter Interleaving

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
let interpret2
    (prog1 : FreeKeyValue<obj,'T>)
    (prog2 : FreeKeyValue<obj,'T>)
    (dataStore : Map<Key,(Version * string)>) 
    : (Map<Key,(Version * string)> * 'T * 'T) =
    let runOne pRun pOther ds =
       match runStep pRun ds with
       | Continue (ds',pRun') -> (pOther, pRun', ds')
       | Complete(ds', a) -> (pOther, Pure a, ds')
        
    let rec loop 
       (p1, p2, ds) =
       match (p1,p2) with
       | (Pure r1, Pure r2) -> (ds,r1, r2)
       | (_, Pure _) -> loop <| runOne p1 p2 ds
       | _ -> loop <| runOne p2 p1 ds

    loop (prog1, prog2, dataStore)

let appendResult2 = 
   interpret2 (appendValue "key" "abcd") (appendValue "key" "abcd") Map.empty
(map [("key", (1, "abcdabcd"))], WriteSuccess, WriteSuccess)

More computation expressions

  • Choice
  • Software Transactional Memory
  • Logging
  • Parsing

References