Module Async_extended.Resource

module Raw : sig ... end
type ('a, 'e) t = ('a'eRaw.t
val create : acquire:(unit ‑> ('a'eCore.Result.t Async_kernel.Deferred.t) ‑> release:('a ‑> unit Async_kernel.Deferred.t) ‑> ('a'et
val with_ : ('a'et ‑> f:('a ‑> 'b Async_kernel.Deferred.t) ‑> ('b'eCore.Result.t Async_kernel.Deferred.t

Access a resource without having to deal with Handle.t explicitly. The resource is acquired before f is called and released after f returns a result or raises an error to the enclosing monitor.

f should not use 'a after it raises or returns, whichever happens first.

Bind corresponds to resource dependency: when acquiring x >>= f, resource x will be acquired, then f is going to be evaluated, then the result of f is going to be acquired. Releases will be done in the opposite order.

include Core.Monad.S2 with type (a, e) t := (a, e) t
type ('a, 'e) t
include Base__.Monad_intf.Infix2 with type (a, e) t := (a, e) t
type ('a, 'e) t
val (>>=) : ('a'et ‑> ('a ‑> ('b'et) ‑> ('b'et
val (>>|) : ('a'et ‑> ('a ‑> 'b) ‑> ('b'et
include Base__.Monad_intf.Syntax2 with type (a, e) t := (a, e) t
type ('a, 'e) t
module Let_syntax : sig ... end
module Monad_infix : Base__.Monad_intf.Infix2 with type (a, e) t := (a, e) t
val bind : ('a'et ‑> f:('a ‑> ('b'et) ‑> ('b'et
val return : 'a ‑> ('a_t
val map : ('a'et ‑> f:('a ‑> 'b) ‑> ('b'et
val join : (('a'et'et ‑> ('a'et
val ignore_m : (_'et ‑> (unit, 'et
val all : ('a'et list ‑> ('a list, 'et
val all_unit : (unit, 'et list ‑> (unit, 'et
val all_ignore : (unit, 'et list ‑> (unit, 'et
  • Deprecated [since 2018-02] Use [all_unit]
val map_error : ('a'e1t ‑> f:('e1 ‑> 'e2) ‑> ('a'e2t
val fail : 'e ‑> ('a'et
val shared : ('a'et ‑> ('a'et

The idea is the following: If you try to acquire a shared resource that's already been acquired, but not yet released then, instead of acquiring it again, you use the value acquired earlier. You only release the underlying resource when all handles to the shared resource get released.

More precisely, if y = shared x and x is exclusively used here then: (i) every activation of y is enclosed into an activation of x; (ii) at any time there is at most one activation of x; (iii) activations of x are as short as possible otherwise.

Beware shared is not referentially transparent in that acquire (shared x) followed by acquire (shared x) will acquire x twice, so you always want to bind the result to a variable: let y = shared x in ... (* acquire y multiple times *)

As an example of what you can do with this, in dart library shared lets us:

In general, it might be helpful when:

module Memo : functor (Key : Core.Hashable) -> sig ... end
val delayed_release : ('a'et ‑> delay:Core.Time.Span.t ‑> ('a'et

Delay all releases by the given amount and don't wait for them