suspension.ml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51(**************************************************************************) (* *) (* OCaml *) (* *) (* Simon Cruanes *) (* *) (* Copyright 2017 Institut National de Recherche en Informatique et *) (* en Automatique. *) (* *) (* All rights reserved. This file is distributed under the terms of *) (* the GNU Lesser General Public License version 2.1, with the *) (* special exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) type 'a suspension = unit -> 'a (* Conversions. *) let to_lazy : 'a suspension -> 'a Lazy.t = Lazy.from_fun (* fun s -> lazy (s()) *) let from_lazy (s : 'a Lazy.t) : 'a suspension = fun () -> Lazy.force s (* [memoize] turns an arbitrary suspension into a persistent suspension. *) let memoize (s : 'a suspension) : 'a suspension = from_lazy (to_lazy s) (* [failure] is a suspension that fails when forced. *) let failure : _ suspension = fun () -> (* A suspension created by [once] has been forced twice. *) raise Seq.Forced_twice (* If [f] is a suspension, then [once f] is a suspension that can be forced at most once. If it is forced more than once, then [Forced_twice] is raised. *) let once (f : 'a suspension) : 'a suspension = let action = Atomic.make f in fun () -> (* Get the function currently stored in [action], and write the function [failure] in its place, so the next access will result in a call to [failure()]. *) let f = Atomic.exchange action failure in f()