Up

Module Resource

Signature

module Raw : sig .. end
type ('a, 'e) t = ('a, 'e) Raw.t
val create : acquire:(unit -> ('a, 'e) Core.Std.Result.t Async_kernel.Std.Deferred.t) -> release:('a -> unit Async_kernel.Std.Deferred.t) -> ('a, 'e) t
val with_ : ('a, 'e) t -> f:('a -> 'b Async_kernel.Std.Deferred.t) -> ('b, 'e) Core.Std.Result.t Async_kernel.Std.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.

include Core.Std.Monad.S2 with type ('a, 'e) t := ('a, 'e) t
type ('a, 'e) t
include Monad_intf.Infix2 with type ('a, 'e) t := ('a, 'e) t
type ('a, 'e) t
val (>>=) : ('a, 'e) t -> ('a -> ('b, 'e) t) -> ('b, 'e) t
val (>>|) : ('a, 'e) t -> ('a -> 'b) -> ('b, 'e) t
include Monad_intf.Syntax2 with type ('a, 'e) t := ('a, 'e) t
type ('a, 'e) t
module Let_syntax : sig .. end
module Monad_infix : Monad_intf.Infix2 with type ('a, 'e) t := ('a, 'e) t
val bind : ('a, 'e) t -> ('a -> ('b, 'e) t) -> ('b, 'e) t
val return : 'a -> ('a, _) t
val map : ('a, 'e) t -> f:('a -> 'b) -> ('b, 'e) t
val join : (('a, 'e) t, 'e) t -> ('a, 'e) t
val ignore_m : (_, 'e) t -> (unit, 'e) t
val all : ('a, 'e) t list -> ('a list, 'e) t
val all_ignore : (unit, 'e) t list -> (unit, 'e) t
val map_error : ('a, 'e1) t -> f:('e1 -> 'e2) -> ('a, 'e2) t
val fail : 'e -> ('a, 'e) t
val shared : ('a, 'e) t -> ('a, 'e) t

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:

  • Coalesce multiple requests for the same entitlement by the same user into one.
  • Only establish up to one connection to dart server per user.

In general, it might be helpful when:

  • If acquiring the original resource is costly;
  • If acquiring x multiple times concurrently is not safe;
  • If multiple acquirings of x would block each other;
  • <your idea>.
module Memo (Key : Core.Std.Hashable) : sig .. end
val delayed_release : ('a, 'e) t -> delay:Core.Std.Time.Span.t -> ('a, 'e) t

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