The stack of bind left-hand sides currently in effect is the current "scope". In order to create a function in one scope and apply it in a different scope, one must manually save and restore the scope. Essentially, the scope should be part of every closure that constructs incrementals. For example:
bind t1 (fun i1 ->
let f t2 = map t2 ~f:(fun i2 -> i1 + i2) in
bind t3 ~f:(fun i -> ... f ...);
bind t4 ~f:(fun i -> ... f ...));
In the above code, the calls to f
will create a map node that unnecessarily
depends on the left-hand side of the most recent bind (t3
or t4
). To eliminate
the unnecessary dependence, one should save and restore the scope for f
:
bind t1 (fun i1 ->
let scope = Scope.current () in
let f t2 = Scope.within scope ~f:(fun () -> map t2 ~f:(fun i2 -> i1 + i2)) in
bind t3 ~f:(fun i -> ... f ...);
bind t4 ~f:(fun i -> ... f ...))
lazy_from_fun
and memoize_fun
capture some common situations in which one would
otherwise need to use Scope.within
.
top
is the toplevel scope.
current ()
returns the scope in which a node would be created right now.
within t f
runs f
in scope t
, which causes all nodes created by f
to be in
scope t
. An exception raised by f
will be raised by within
in the usual
way.