F# Implementation of Scala ZIO

PLEASE NOTE SOURCE CODE IS NO LONGER AVAILABLE AND THE POST IS HERE JUST FOR INFORMATION

This is a prototype implementation of Scala ZIO in F#. It aims to be a skeleton of ZIO features such that additional functions can be easily fleshed out.

I recently went to a talk on Scala ZIO by John De Goes. ZIO is a type-safe, composable library for asynchronous and concurrent programming in Scala.

It takes a different approach to other Scala effects libraries in that it does not require the use of Higher-Kinded Types. Instead it uses a reader monad to provide access to IO effects (called ZIO Environment).

I came away wanting something similar in F#. A useful library that could be used in the outer IO layer to simplify and test IO dependency code. I started to play with some reader code but didn't think it would ultimately work out. In fact, it works really well.

\[IO = Reader + Async + Result\]

The F# equivalent of ZIO type aliases are UIO<'r,'a> which represents effects without errors, and IO<'r,'a,'e> which represents effects with a possible error. IO combines reader, async and result into one unified computation expression.

type UIO < ' r , ' a > = UIO of ( ' r * Cancel -> ( ' a option -> unit ) -> unit )

type IO < ' r , ' a , ' e > = IO of ( ' r * Cancel -> ( Result < ' a , ' e > option -> unit ) -> unit )

The reader part represents all the environment dependencies required in the computation expression. It is fully type-safe with types inferred including any library requirements such as Clock for the timeout. The computation expression can easily be tested by running with a test environment.

At the IO layer thread pool threads need to be used in the most efficient way without any blocking. This usually means Async in F# or async/await in C# need to be used. They both join threads without a thread pool thread having to wait.

let ( UIO ) ( IO ) : IO < ' r , Choice < ' a1 , ' a2 > , ' e1 > = IO ( fun env -> if Cancel . isSet env then None else let envChild = Cancel . add env let mutable o = 0 ThreadPool . QueueUserWorkItem ( fun _ -> envChild ( fun a -> if Interlocked . Exchange ( & o , 1 ) = 0 then Cancel . set envChild if Cancel . isSet env then None else Option . map ( Choice2Of2 > > Ok ) a |> ) ) |> ThreadPool . QueueUserWorkItem ( fun _ -> envChild ( fun a -> if Interlocked . Exchange ( & o , 1 ) = 0 then Cancel . set envChild if Cancel . isSet env then None else Option . map ( Result . map Choice1Of2 ) a |> ) ) |> )

With IO async is implemented directly using the thread pool. There are two main reasons for this. In IO exceptions are not part of control flow. Errors are first class and type-safe. Unrecoverable exceptions output the stack trace and exit the process. Cancellation is fully integrated into IO meaning in race, parallel and upon an error, computations are automatically cancelled, saving resources.

These with the final part dramatically simplify and optimise asynchronous IO code.

The result part of IO represents possible errors in an integrated and type-safe way. The error type is inferred, and different error types are auto lifted into Choice<'a,'b> when combined. IO computations can be timed out and retried based on result using simple functions. Schedule is a powerful construct that can be combined several ways. I've replicated the structure from ZIO but not fully explored its uses.

let noRetry = io { do! Logger . log "started" do! Console . writeLine "Please enter your name:" let! name = Console . readLine ( ) do! Logger . log ( "got name = " + name ) let! thread = Persistence . persist name |> IO . timeout 1000 |> IO . retry ( Schedule . recurs noRetry ) |> IO . fork do! Console . writeLine ( "Hi " + name ) do! thread do! Logger . log "finished" return 0 }

When type inference worked for the dependencies I was surprised. When it was also possible to make it work for the errors I was amazed.

Computation expressions do not compose well. At the IO layer a solution is needed for dependencies in a testable way. The IO layer also needs to efficiently use the thread pool. Making errors type-safe and integrated in the IO logic completes this compelling trinity.

IO.fs

IOTests.fs

ZIO Overview

ZIO Data Types

The Death Of Final Tagless

@jdegoes for ZIO and a great talk that made me want to do this.

@NinoFloris for useful async discussions.

@keithtpinson for the error auto lift idea.

Multiple items

module Result



from Microsoft.FSharp.Core



--------------------

[<Struct>]

type Result<'T,'TError> =

| Ok of ResultValue: 'T

| Error of ErrorValue: 'TError

union case Result.Ok: 'a -> Result<'a,'e>

union case Result.Error: 'e -> Result<'a,'e>

Multiple items

module Result



from Microsoft.FSharp.Core



--------------------

type Result<'a,'e> =

| Ok of 'a

| Error of 'e

val map : f:('a -> 'b) -> Result<'a,'e> -> Result<'b,'e>

val f : ('a -> 'b)

val failwith : message:string -> 'T

val mapError : f:('e -> 'f) -> Result<'a,'e> -> Result<'a,'f>

val f : ('e -> 'f)

Multiple items

union case Time.Time: Time



--------------------

type Time = | Time

val now : unit -> Time

Multiple items

type Choice<'T1,'T2> =

| Choice1Of2 of 'T1

| Choice2Of2 of 'T2



--------------------

type Choice<'T1,'T2,'T3> =

| Choice1Of3 of 'T1

| Choice2Of3 of 'T2

| Choice3Of3 of 'T3



--------------------

type Choice<'T1,'T2,'T3,'T4> =

| Choice1Of4 of 'T1

| Choice2Of4 of 'T2

| Choice3Of4 of 'T3

| Choice4Of4 of 'T4



--------------------

type Choice<'T1,'T2,'T3,'T4,'T5> =

| Choice1Of5 of 'T1

| Choice2Of5 of 'T2

| Choice3Of5 of 'T3

| Choice4Of5 of 'T4

| Choice5Of5 of 'T5



--------------------

type Choice<'T1,'T2,'T3,'T4,'T5,'T6> =

| Choice1Of6 of 'T1

| Choice2Of6 of 'T2

| Choice3Of6 of 'T3

| Choice4Of6 of 'T4

| Choice5Of6 of 'T5

| Choice6Of6 of 'T6



--------------------

type Choice<'T1,'T2,'T3,'T4,'T5,'T6,'T7> =

| Choice1Of7 of 'T1

| Choice2Of7 of 'T2

| Choice3Of7 of 'T3

| Choice4Of7 of 'T4

| Choice5Of7 of 'T5

| Choice6Of7 of 'T6

| Choice7Of7 of 'T7

val merge : c:Choice<'a,'a> -> 'a

val c : Choice<'a,'a>

union case Choice.Choice1Of2: 'T1 -> Choice<'T1,'T2>

val a : 'a

union case Choice.Choice2Of2: 'T2 -> Choice<'T1,'T2>

namespace System

namespace System.Threading

Multiple items

union case Cancel.Cancel: bool ref * children: Cancel list ref -> Cancel



--------------------

type Cancel = private | Cancel of bool ref * children: Cancel list ref

type bool = System.Boolean

Multiple items

val ref : value:'T -> 'T ref



--------------------

type 'T ref = Ref<'T>

type 'T list = List<'T>

val internal isSet : 'r * Cancel -> bool

val i : bool ref

val internal create : unit -> Cancel

val internal add : r:'r * Cancel -> 'r * Cancel

val r : 'r

val c : Cancel list ref

val i : Cancel

val internal set : r:'a * Cancel -> unit

val r : 'a

val me : bool ref

val kids : Cancel list ref

Multiple items

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 iter : action:('T -> unit) -> list:'T list -> unit

Multiple items

union case UIO.UIO: ('r * Cancel -> ('a option -> unit) -> unit) -> UIO<'r,'a>



--------------------

type UIO<'r,'a> =

| UIO of ('r * Cancel -> ('a option -> unit) -> unit)

member Bind : f:('a -> UIO<'r,'b>) -> UIO<'r,'b>

member Bind : f:('a -> IO<'r,'b,'e>) -> IO<'r,'b,'e>

Multiple items

union case Cancel.Cancel: bool ref * children: Cancel list ref -> Cancel



--------------------

module Cancel



from 2019-03-29-io



--------------------

type Cancel = private | Cancel of bool ref * children: Cancel list ref

type 'T option = Option<'T>

type unit = Unit

val m : UIO<'r,'a>

val f : ('a -> UIO<'r,'b>)

val run : ('r * Cancel -> ('a option -> unit) -> unit)

val env : 'r * Cancel

val cont : ('b option -> unit)

union case Option.None: Option<'T>

val o : 'a option

module Option



from Microsoft.FSharp.Core

val map : mapping:('T -> 'U) -> option:'T option -> 'U option

union case Option.Some: Value: 'T -> Option<'T>

val run : ('r * Cancel -> ('b option -> unit) -> unit)

val result : a:'a -> UIO<'r,'a>

val cont : ('a option -> unit)

val effect : f:('r -> 'a) -> UIO<'r,'a>

val f : ('r -> 'a)

val fst : tuple:('T1 * 'T2) -> 'T1

val map : f:('a -> 'b) -> UIO<'r,'a> -> UIO<'r,'b>

val b : 'b

val delay : milliseconds:int -> UIO<'r,unit>

val milliseconds : int

val cont : (unit option -> unit)

val mutable t : Timer

module Unchecked



from Microsoft.FSharp.Core.Operators

val defaultof<'T> : 'T

Multiple items

type Timer =

inherit MarshalByRefObject

new : callback:TimerCallback -> Timer + 4 overloads

member Change : dueTime:int * period:int -> bool + 3 overloads

member Dispose : unit -> unit + 1 overload



--------------------

Timer(callback: TimerCallback) : Timer

Timer(callback: TimerCallback, state: obj, dueTime: int, period: int) : Timer

Timer(callback: TimerCallback, state: obj, dueTime: System.TimeSpan, period: System.TimeSpan) : Timer

Timer(callback: TimerCallback, state: obj, dueTime: uint32, period: uint32) : Timer

Timer(callback: TimerCallback, state: obj, dueTime: int64, period: int64) : Timer

Timer.Dispose() : unit

Timer.Dispose(notifyObject: WaitHandle) : bool

type Timeout =

static val InfiniteTimeSpan : TimeSpan

static val Infinite : int

field Timeout.Infinite: int = -1

val flatten : f:('r -> UIO<'r,'a>) -> UIO<'r,'a>

val f : ('r -> UIO<'r,'a>)

val t : 'a option

val toAsync : env:'r -> UIO<'r,'a> -> Async<'a>

val env : 'r

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

static member Async.FromContinuations : callback:(('T -> unit) * (exn -> unit) * (System.OperationCanceledException -> unit) -> unit) -> Async<'T>

val cont : ('a -> unit)

property Option.Value: 'a

val fork : UIO<'r,'a> -> UIO<'r,UIO<'r,'a>>

val contFork : (UIO<'r,'a> option -> unit)

val mutable o : obj

type ThreadPool =

static member BindHandle : osHandle:nativeint -> bool + 1 overload

static member GetAvailableThreads : workerThreads:int * completionPortThreads:int -> unit

static member GetMaxThreads : workerThreads:int * completionPortThreads:int -> unit

static member GetMinThreads : workerThreads:int * completionPortThreads:int -> unit

static member QueueUserWorkItem : callBack:WaitCallback -> bool + 1 overload

static member RegisterWaitForSingleObject : waitObject:WaitHandle * callBack:WaitOrTimerCallback * state:obj * millisecondsTimeOutInterval:uint32 * executeOnlyOnce:bool -> RegisteredWaitHandle + 3 overloads

static member SetMaxThreads : workerThreads:int * completionPortThreads:int -> bool

static member SetMinThreads : workerThreads:int * completionPortThreads:int -> bool

static member UnsafeQueueNativeOverlapped : overlapped:NativeOverlapped -> bool

static member UnsafeQueueUserWorkItem : callBack:WaitCallback * state:obj -> bool

...

ThreadPool.QueueUserWorkItem(callBack: WaitCallback) : bool

ThreadPool.QueueUserWorkItem(callBack: WaitCallback, state: obj) : bool

val a : 'a option

val o : obj

type Interlocked =

static member Add : location1:int * value:int -> int + 1 overload

static member CompareExchange : location1:int * value:int * comparand:int -> int + 6 overloads

static member Decrement : location:int -> int + 1 overload

static member Exchange : location1:int * value:int -> int + 6 overloads

static member Increment : location:int -> int + 1 overload

static member MemoryBarrier : unit -> unit

static member Read : location:int64 -> int64

Interlocked.CompareExchange<'T (requires reference type)>(location1: byref<'T>, value: 'T, comparand: 'T) : 'T

Interlocked.CompareExchange(location1: byref<nativeint>, value: nativeint, comparand: nativeint) : nativeint

Interlocked.CompareExchange(location1: byref<obj>, value: obj, comparand: obj) : obj

Interlocked.CompareExchange(location1: byref<float>, value: float, comparand: float) : float

Interlocked.CompareExchange(location1: byref<float32>, value: float32, comparand: float32) : float32

Interlocked.CompareExchange(location1: byref<int64>, value: int64, comparand: int64) : int64

Interlocked.CompareExchange(location1: byref<int>, value: int, comparand: int) : int

val isNull : value:'T -> bool (requires 'T : null)

val not : value:bool -> bool

val cont : (Option<'a> -> unit)

val ignore : value:'T -> unit

type ClockService =

interface

abstract member Sleep : int -> UIO<'r,unit>

abstract member Time : unit -> UIO<'r,Time>

end

Multiple items

module Time



from 2019-03-29-io



--------------------

type Time = | Time

Multiple items

union case UIO.UIO: ('r * Cancel -> ('a option -> unit) -> unit) -> UIO<'r,'a>



--------------------

module UIO



from 2019-03-29-io



--------------------

type UIO<'r,'a> =

| UIO of ('r * Cancel -> ('a option -> unit) -> unit)

member Bind : f:('a -> UIO<'r,'b>) -> UIO<'r,'b>

member Bind : f:('a -> IO<'r,'b,'e>) -> IO<'r,'b,'e>

Multiple items

val int : value:'T -> int (requires member op_Explicit)



--------------------

type int = int32



--------------------

type int<'Measure> = int

type Clock =

interface

abstract member Clock : ClockService

end

val time : unit -> UIO<#Clock,Time>

val c : #Clock

property Clock.Clock: ClockService

abstract member ClockService.Time : unit -> UIO<'r,Time>

val sleep : milliseconds:int -> UIO<#Clock,unit>

abstract member ClockService.Sleep : int -> UIO<'r,unit>

val liveService : ClockService

Multiple items

union case Time.Time: Time



--------------------

module Time



from 2019-03-29-io



--------------------

type Time = | Time

val __ : ClockService

Multiple items

union case Decision.Decision: cont: bool * delay: int * state: 'a * (unit -> 'b) -> Decision<'a,'b>



--------------------

type Decision<'a,'b> = | Decision of cont: bool * delay: int * state: 'a * (unit -> 'b)

Multiple items

union case Schedule.Schedule: initial: UIO<'r,'s> * update: 'a * 's -> UIO<'r,Decision<'s,'b>> -> Schedule<'r,'s,'a,'b>



--------------------

type Schedule<'r,'s,'a,'b> = private | Schedule of initial: UIO<'r,'s> * update: 'a * 's -> UIO<'r,Decision<'s,'b>>

val forever<'r,'a> : Schedule<'r,int,'a,int>

val s : int

val private updated : update:(('a * 's -> UIO<'r,Decision<'s,'b>>) -> 'a * 's -> UIO<'r,Decision<'s,'b2>>) -> Schedule<'r,'s,'a,'b> -> Schedule<'r,'s,'a,'b2>

val update : (('a * 's -> UIO<'r,Decision<'s,'b>>) -> 'a * 's -> UIO<'r,Decision<'s,'b2>>)

val i : UIO<'r,'s>

val u : ('a * 's -> UIO<'r,Decision<'s,'b>>)

val private check : test:('a * 'b -> UIO<'r,bool>) -> m:Schedule<'r,'a0,'a,'b> -> Schedule<'r,'a0,'a,'b>

val test : ('a * 'b -> UIO<'r,bool>)

val m : Schedule<'r,'a,'a0,'b>

val update : ('a * 'a0 -> UIO<'r,Decision<'a0,'b>>)

val s : 'a

val cont : bool

val dur : int

val a1 : 'a

val fb : (unit -> 'b)

val d : Decision<'a,'b>

val b : bool

val whileOutput : f:('b -> bool) -> m:Schedule<'a,'b0,'c,'b> -> Schedule<'a,'b0,'c,'b>

val f : ('b -> bool)

val m : Schedule<'a,'b,'c,'b0>

val recurs : n:int -> Schedule<'a,int,'b,int>

val n : int

val i : int

Multiple items

union case IO.IO: ('r * Cancel -> (Result<'a,'e> option -> unit) -> unit) -> IO<'r,'a,'e>



--------------------

type IO<'r,'a,'e> =

| IO of ('r * Cancel -> (Result<'a,'e> option -> unit) -> unit)

member Bind : f:('a -> UIO<'r,'b>) -> IO<'r,'b,'e>

member Bind : f:('a -> IO<'r,'b,'e>) -> IO<'r,'b,'e>

member Bind : f:('a -> IO<'r,'b,'e2>) -> IO<'r,'b,Choice<'e,'e2>>

Multiple items

module Result



from 2019-03-29-io



--------------------

module Result



from Microsoft.FSharp.Core



--------------------

type Result<'a,'e> =

| Ok of 'a

| Error of 'e

val m : IO<'r,'a,'e>

val run : ('r * Cancel -> (Result<'a,'e> option -> unit) -> unit)

val cont : (Result<'b,'e> option -> unit)

val o : Result<'a,'e> option

val o : 'b option

val e : 'e

val f : ('a -> IO<'r,'b,'e>)

val run : ('r * Cancel -> (Result<'b,'e> option -> unit) -> unit)

val f : ('a -> IO<'r,'b,'e2>)

Multiple items

module Choice



from 2019-03-29-io



--------------------

type Choice<'T1,'T2> =

| Choice1Of2 of 'T1

| Choice2Of2 of 'T2



--------------------

type Choice<'T1,'T2,'T3> =

| Choice1Of3 of 'T1

| Choice2Of3 of 'T2

| Choice3Of3 of 'T3



--------------------

type Choice<'T1,'T2,'T3,'T4> =

| Choice1Of4 of 'T1

| Choice2Of4 of 'T2

| Choice3Of4 of 'T3

| Choice4Of4 of 'T4



--------------------

type Choice<'T1,'T2,'T3,'T4,'T5> =

| Choice1Of5 of 'T1

| Choice2Of5 of 'T2

| Choice3Of5 of 'T3

| Choice4Of5 of 'T4

| Choice5Of5 of 'T5



--------------------

type Choice<'T1,'T2,'T3,'T4,'T5,'T6> =

| Choice1Of6 of 'T1

| Choice2Of6 of 'T2

| Choice3Of6 of 'T3

| Choice4Of6 of 'T4

| Choice5Of6 of 'T5

| Choice6Of6 of 'T6



--------------------

type Choice<'T1,'T2,'T3,'T4,'T5,'T6,'T7> =

| Choice1Of7 of 'T1

| Choice2Of7 of 'T2

| Choice3Of7 of 'T3

| Choice4Of7 of 'T4

| Choice5Of7 of 'T5

| Choice6Of7 of 'T6

| Choice7Of7 of 'T7

val cont : (Result<'b,Choice<'e,'e2>> option -> unit)

val bind : ('r * Cancel -> (Result<'b,'e2> option -> unit) -> unit)

val o : Result<'b,'e2> option

val b : Result<'b,Choice<'e,'e2>> option

Multiple items

val mapError : f:('e -> 'f) -> Result<'a,'e> -> Result<'a,'f>



--------------------

val mapError : mapping:('TError -> 'U) -> result:Result<'T,'TError> -> Result<'T,'U>

val bind : ('r * Cancel -> (Result<'b,'e> option -> unit) -> unit)

val ok : a:'a -> IO<'r,'a,'e>

val cont : (Result<'a,'e> option -> unit)

val error : e:'e -> IO<'r,'a,'e>

val result : a:Result<'a,'e> -> IO<'r,'a,'e>

val a : Result<'a,'e>

val effect : f:('r -> Result<'a,'e>) -> IO<'r,'a,'e>

val f : ('r -> Result<'a,'e>)

val map : f:('a -> 'b) -> IO<'r,'a,'e> -> IO<'r,'b,'e>

val b : Result<'b,'e> option

Multiple items

val map : f:('a -> 'b) -> Result<'a,'e> -> Result<'b,'e>



--------------------

val map : mapping:('T -> 'U) -> result:Result<'T,'TError> -> Result<'U,'TError>

val mapError : f:('e -> 'e2) -> IO<'r,'a,'e> -> IO<'r,'a,'e2>

val f : ('e -> 'e2)

val cont : (Result<'a,'e2> option -> unit)

val b : Result<'a,'e2> option

val mapResult : f:(Result<'a,'e> -> Result<'b,'e2>) -> IO<'r,'a,'e> -> IO<'r,'b,'e2>

val f : (Result<'a,'e> -> Result<'b,'e2>)

val cont : (Result<'b,'e2> option -> unit)

val b : Result<'b,'e2> option

val private foldM : succ:('a -> IO<'r,'b,'e2>) -> err:('e -> IO<'r,'b,'e2>) -> IO<'r,'a,'e> -> IO<'r,'b,'e2>

val succ : ('a -> IO<'r,'b,'e2>)

val err : ('e -> IO<'r,'b,'e2>)

val run : ('r * Cancel -> (Result<'b,'e2> option -> unit) -> unit)

val private retryOrElse : Schedule<'r,'s,'e,'a> -> orElse:('e * 's -> IO<'r,'b,'e2>) -> io:IO<'r,'a0,'e> -> IO<'r,Choice<'a0,'b>,'e2> (requires 'r :> Clock)

Multiple items

union case Schedule.Schedule: initial: UIO<'r,'s> * update: 'a * 's -> UIO<'r,Decision<'s,'b>> -> Schedule<'r,'s,'a,'b>



--------------------

module Schedule



from 2019-03-29-io



--------------------

type Schedule<'r,'s,'a,'b> = private | Schedule of initial: UIO<'r,'s> * update: 'a * 's -> UIO<'r,Decision<'s,'b>>

val initial : UIO<#Clock,'s>

val update : ('e * 's -> UIO<#Clock,Decision<'s,'a>>)

val orElse : ('e * 's -> IO<#Clock,'b,'e2>)

val io : IO<#Clock,'a,'e>

val loop : ('s -> IO<#Clock,Choice<'a,'b>,'e2>)

val state : 's

val u : UIO<#Clock,Decision<'s,'a>>

member UIO.Bind : f:('a -> UIO<'r,'b>) -> UIO<'r,'b>

member UIO.Bind : f:('a -> IO<'r,'b,'e>) -> IO<'r,'b,'e>

val delay : int

Multiple items

module Clock



from 2019-03-29-io



--------------------

type Clock =

interface

abstract member Clock : ClockService

end

val retry : policy:Schedule<'r,'s,'e,'sb> -> io:IO<'r,'a,'e> -> IO<'r,'a,'e> (requires 'r :> Clock)

val policy : Schedule<#Clock,'s,'e,'sb>

val fork : IO<'r,'a,'e> -> UIO<'r,IO<'r,'a,'e>>

val contFork : (IO<'r,'a,'e> option -> unit)

val a : Result<'a,'e> option

val para : ios:IO<'r,'a,'e> [] -> IO<'r,'a [],'e>

val ios : IO<'r,'a,'e> []

val cont : (Result<'a [],'e> option -> unit)

val envChild : 'r * Cancel

val results : 'a []

module Array



from Microsoft.FSharp.Collections

val zeroCreate : count:int -> 'T []

property System.Array.Length: int

val mutable count : int

val iteri : action:(int -> 'T -> unit) -> array:'T [] -> unit

val io : IO<'r,'a,'e>

Interlocked.Decrement(location: byref<int64>) : int64

Interlocked.Decrement(location: byref<int>) : int

Interlocked.Exchange<'T (requires reference type)>(location1: byref<'T>, value: 'T) : 'T

Interlocked.Exchange(location1: byref<nativeint>, value: nativeint) : nativeint

Interlocked.Exchange(location1: byref<obj>, value: obj) : obj

Interlocked.Exchange(location1: byref<float>, value: float) : float

Interlocked.Exchange(location1: byref<float32>, value: float32) : float32

Interlocked.Exchange(location1: byref<int64>, value: int64) : int64

Interlocked.Exchange(location1: byref<int>, value: int) : int

val race : UIO<'r,'a2> -> IO<'r,'a1,'e1> -> IO<'r,Choice<'a1,'a2>,'e1>

val run1 : ('r * Cancel -> ('a2 option -> unit) -> unit)

val run2 : ('r * Cancel -> (Result<'a1,'e1> option -> unit) -> unit)

val cont : (Result<Choice<'a1,'a2>,'e1> option -> unit)

val mutable o : int

val a : 'a2 option

val a : Result<'a1,'e1> option

val timeout : milliseconds:int -> io:IO<'r,'a,'e> -> IO<'r,'a,'e option> (requires 'r :> Clock)

val env : #Clock * Cancel

val cont : (Result<'a,'e option> option -> unit)

val run : (#Clock * Cancel -> (Result<Choice<'a,unit>,'e> option -> unit) -> unit)

val o : Result<Choice<'a,unit>,'e> option

val toAsync : env:'r -> IO<'r,'a,'e> -> Async<Result<'a,'e>>

val cont : (Result<'a,'e> -> unit)

property Option.Value: Result<'a,'e>

Multiple items

type IOBuilder =

new : unit -> IOBuilder

member Bind : io:UIO<'r,'a> * f:('a -> UIO<'r,'b>) -> UIO<'r,'b>

member Bind : io:IO<'r,'a,'e> * f:('a -> UIO<'r,'b>) -> IO<'r,'b,'e>

member Bind : io:UIO<'r,'a> * f:('a -> IO<'r,'b,'e>) -> IO<'r,'b,'e>

member Bind : io:IO<'r,'a,'e> * f:('a -> IO<'r,'b,'e>) -> IO<'r,'b,'e>

member Bind : io:IO<'r,'a,'e1> * f:('a -> IO<'r,'b,'e2>) -> IO<'r,'b,Choice<'e1,'e2>>

member Return : value:'b -> UIO<'c,'b>

member ReturnFrom : value:'a -> 'a



--------------------

new : unit -> IOBuilder

val io : UIO<'r,'a>

val __ : IOBuilder

Multiple items

union case IO.IO: ('r * Cancel -> (Result<'a,'e> option -> unit) -> unit) -> IO<'r,'a,'e>



--------------------

module IO



from 2019-03-29-io



--------------------

type IO<'r,'a,'e> =

| IO of ('r * Cancel -> (Result<'a,'e> option -> unit) -> unit)

member Bind : f:('a -> UIO<'r,'b>) -> IO<'r,'b,'e>

member Bind : f:('a -> IO<'r,'b,'e>) -> IO<'r,'b,'e>

member Bind : f:('a -> IO<'r,'b,'e2>) -> IO<'r,'b,Choice<'e,'e2>>

member IO.Bind : f:('a -> UIO<'r,'b>) -> IO<'r,'b,'e>

member IO.Bind : f:('a -> IO<'r,'b,'e>) -> IO<'r,'b,'e>

member IO.Bind : f:('a -> IO<'r,'b,'e2>) -> IO<'r,'b,Choice<'e,'e2>>

val io : IO<'r,'a,'e1>

val value : 'b

val value : 'a

Multiple items

type AutoOpenAttribute =

inherit Attribute

new : unit -> AutoOpenAttribute

new : path:string -> AutoOpenAttribute

member Path : string



--------------------

new : unit -> AutoOpenAttribute

new : path:string -> AutoOpenAttribute

val io : IOBuilder

Multiple items

union case ConsoleError.ConsoleError: ConsoleError



--------------------

type ConsoleError = | ConsoleError

type ConsoleService =

interface

abstract member ReadLine : unit -> Result<string,ConsoleError>

abstract member WriteLine : string -> unit

end

Multiple items

val string : value:'T -> string



--------------------

type string = System.String

type Console =

interface

abstract member Console : ConsoleService

end

val writeLine : s:string -> UIO<#Console,unit>

val s : string

val c : #Console

property Console.Console: ConsoleService

abstract member ConsoleService.WriteLine : string -> unit

val readLine : unit -> IO<#Console,string,ConsoleError>

abstract member ConsoleService.ReadLine : unit -> Result<string,ConsoleError>

type LoggingService =

interface

abstract member Log : string -> unit

end

type Logger =

interface

abstract member Logging : LoggingService

end

val log : s:string -> UIO<#Logger,unit>

val l : #Logger

property Logger.Logging: LoggingService

abstract member LoggingService.Log : string -> unit

Multiple items

union case PersistError.PersistError: PersistError



--------------------

type PersistError = | PersistError

type PersistenceService =

interface

abstract member Persist : 'a -> Result<unit,PersistError>

end

type Persistence =

interface

abstract member Persistence : PersistenceService

end

val persist : a:'a -> IO<#Persistence,unit,PersistError>

val p : #Persistence

property Persistence.Persistence: PersistenceService

abstract member PersistenceService.Persist : 'a -> Result<unit,PersistError>

val programRetry : noRetry:int -> IO<'r,int,Choice<ConsoleError,PersistError option>> (requires 'r :> Logger and 'r :> Clock and 'r :> Persistence and 'r :> Console)

val noRetry : int

Multiple items

module Logger



from 2019-03-29-io



--------------------

type Logger =

interface

abstract member Logging : LoggingService

end

Multiple items

module Console



from 2019-03-29-io



--------------------

type Console =

interface

abstract member Console : ConsoleService

end

val name : string

val thread : IO<'r,unit,PersistError option> (requires 'r :> Logger and 'r :> Clock and 'r :> Persistence and 'r :> Console)

Multiple items

module Persistence



from 2019-03-29-io



--------------------

type Persistence =

interface

abstract member Persistence : PersistenceService

end