Module Ui_effect

module type Handler = sig ... end
module type S = sig ... end
type 'a t = ..

'a Effect.t represents some computation of type 'a that can be performed outside of the typical computational/incremental structure of a Bonsai program . Examples of this computation might be:

  • Calling an RPC and getting the result back
  • Running expensive computation on a web-worker thread
  • Requesting some information from the imperative "Start.Handle"-holding code

If you have a value of type 'a Effect.t, you can schedule it to be run by calling inject and providing a function that will be called when the callback completes.

type t +=
  1. | Ignore : Base.unit t
  2. | Many : Base.unit t Base.list -> Base.unit t
include Base.Monad.S with type 'a t := 'a t
val return : 'a 'i 'p 'q. 'a -> 'a t

Convert a value to a t.

val map : 'a 'b 'i 'j 'p 'q. 'a t -> f:('a -> 'b) -> 'b t

Transforms the contents of a t.

val bind : 'a 'b 'i 'j 'k 'p 'q. 'a t -> f:('a -> 'b t) -> 'b t

Sequences computations. bind t ~f computes f v for value(s) v in t. Well-behaved monads satisfy these "laws" (where ( >>= ) is the infix bind operator):

  • map t ~f is equivalent to bind t ~f:(fun x -> return (f x))
  • return x >>= f is equivalent to f x
  • t >>= return is equivalent to t
  • (t >>= f) >>= g is equivalent to t >>= fun x -> f x >>= g
val join : 'a 'i 'j 'k 'p 'q. 'a t t -> 'a t

Combines nested t into just one layer. Equivalent to bind t ~f:Fn.id.

val ignore_m : 'a 'i 'j 'p 'q. 'a t -> unit t

Ignores contained values of t. Equivalent to map t ~f:ignore.

val all : 'a 'i 'p 'q. 'a t list -> 'a list t

Combines a list of t.

val all_unit : 'i 'p 'q. unit t list -> unit t

Combines a list of t whose contents are unimportant.

val (>>=) : 'a 'b 'i 'j 'k 'p 'q. 'a t -> ('a -> 'b t) -> 'b t

Infix bind.

val (>>|) : 'a 'b 'i 'j 'p 'q. 'a t -> ('a -> 'b) -> 'b t

Infix map.

module Monad_infix : sig ... end
module Let_syntax : sig ... end
module Par : Base.Monad.S with type 'a t := 'a t

The Par module contains a Let_syntax whose both function executes the effects in parallel.

val never : 'a t

An effect that never completes

val raise : Base.exn -> 'a t

Produces an effect that raises an exception when the effect is performed.

Note: As long as this is handled by either try_with/try_with_or_error or Expert.handle/Expert.eval (with a non-raising on_exn), no exceptions will ever actually be raised. This should be safe to use in environments where raising exceptions is costly (or at the very least, better than raising directly).

val raise_s : Base.Sexp.t -> 'a t
val raise_error : Base.Error.t -> 'a t
val lower_result : ('a, Base.Exn.t) Base.Result.t t -> 'a t

Like Result.ok_exn, except with the performance-friendly properties of raise.

val lower_or_error : 'a Base.Or_error.t t -> 'a t

Like Or_error.ok_exn, except with the performance-friendly properties of raise_error.

val try_with : ?rest:[ `Raise | `Call of Base.Exn.t -> Base.unit ] -> 'a t -> ('a, Base.Exn.t) Base.Result.t t

If evaluating the given effect produces an exception before producing a value, try_with will return the first exn in the error side of the Result.t.

If rest is `Call f, try_with will use f to handle any further exns produced. Otherwise, they will be raised further (i.e. visible to iter_errors, try_with, and eventual Expert.handle/Expert.eval calls), although they cannot cause the effect itself to raise (i.e. further try_withs will result in Ok and handle them via its rest parameter).

val try_with_or_error : ?rest:[ `Raise | `Call of Base.Exn.t -> Base.unit ] -> 'a t -> 'a Base.Or_error.t t

Like try_with, but returns the exn as an Error.t.

val iter_errors : 'a t -> f:(Base.Exn.t -> Base.unit t) -> 'a t

If exceptions are produced in the course of evaluating the input effect, the function passed to iter_errors will be invoked with those errors. Multiple errors can be produced from functions such as both_parallel, all_parallel, and protect. This doesn't _handle_ the errors, but you can record or print the error. Throwing an exception inside of f will not recursively invoke f on the new error that is produced.

Note that iter_errors only calls f on exns as they are produced; it does not wait for more exns before letting an exn continue to raise. For example, iter_errors (both_parallel (raise a) (raise b)) ~f will evaluate f a, raise a to its next handler, evaluate f b, and then raise b to its next handler.

val protect : 'a t -> finally:Base.unit t -> 'a t

protect runs an effect, and after the effect completes (including if it fails with an exception), it also runs the finally effect.

If the given effect raises an exception, protect will output an effect that also raises that exception after executing finally (even if finally also raises). If finally raises (but not the given effect), the output of protect will raise with that exception.

val both_parallel : 'a t -> 'b t -> ('a * 'b) t

evaluates both effects in parallel and returns their product when both complete

val all_parallel : 'a t Base.list -> 'a Base.list t

evaluates all effects in the list in parallel and returns the list of results when all of them complete. The output list is always the same length as the input list.

val all_parallel_unit : Base.unit t Base.list -> Base.unit t

like all_parallel, but for unit Effect.ts.

val lazy_ : 'a t Base.Lazy.t -> 'a t

If creating an effect could be expensive, you can wrap its construction in a lazy and pass it to this function so that its construction will be deferred until it's about to be evaluated.

val print_s : Base.Sexp.t -> Base.unit t

Prints the sexp when scheduled.

val of_sync_fun : ('query -> 'result) -> 'query -> 'result t

of_sync_fun is similar to of_deferred_fun but with a synchronous function instead of a deferred one. This can be used for functions that are synchronous but side-effecting, or as a mock-function in tests that replace the usages of of_deferred_fun in the actual app.

Note that, unlike of_deferred_fun, the function must return immediately, so it's not possible to test the behaviour of tour app between calling the function and the effect becoming 'determined'. If you need to do this, see of_svar and of_query_response_tracker below.

val of_thunk : (Base.unit -> 'result) -> 'result t

Like of_sync_fun but with a pre-applied unit query. Side-effects in the function will be run every time that the resulting effect is scheduled

val of_sync_fun' : ('query -> on_exn:(Base.Exn.t -> Base.unit) -> 'result) -> 'query -> 'result t

Like of_sync_fun but with an extra on_exn parameter that can be passed into calls to Expert.handle.

val of_thunk' : (Base.unit -> on_exn:(Base.Exn.t -> Base.unit) -> 'result) -> 'result t

Like of_thunk but with an extra on_exn parameter that can be passed into calls to Expert.handle.

module Define (Handler : Handler) : S with type action := Handler.Action.t and type 'a t := 'a t
module Define1 (Handler : sig ... end) : sig ... end
module Expert : sig ... end
module Private : sig ... end
module Result : sig ... end

Result is extremely similar to Deferred.Result

module Or_error : sig ... end

Like Result above, this is extremely similar to Deferred.Or_error. A lot of the additional functions are missing, but can be added as needed

module For_testing : sig ... end