0c6fa68e4c9d draft — orbitz 8 years ago
Move lib to src
A => src/revops/META +6 -0
@@ 0,0 1,6 @@ 
+name="revops"
+version="1.0.0"
+description="Reversible Operations"
+requires="core"
+archive(byte)="revops.cma"
+archive(native)="revops.cmxa"

          
A => src/revops/Makefile +22 -0
@@ 0,0 1,22 @@ 
+CAMLP4=
+
+OCAMLDEP_OPTS=
+OCAMLC_OPTS=$(OCAMLDEP_OPTS) -w '@f@p@u@s@40' -package core
+OCAMLOPT_OPTS=$(OCAMLC_OPTS)
+
+LIB_MODULES=revops.ml revops_fn.ml revops_sys.ml revops_univ.ml revops_univ_fn.ml
+NON_LIB_MODULES=revops_intf.ml revops_univ_intf.ml
+
+BYTE_TARGETS=revops.cma
+NATIVE_TARGETS=revops.cmxa
+
+.PHONY: all test install
+
+all: native-code byte-code
+
+test:
+
+install: install_lib
+
+# Dependencies
+include ../Ocamlrules.mk.in

          
A => src/revops/revops.ml +13 -0
@@ 0,0 1,13 @@ 
+(* Implementation for reversible operations. *)
+
+open Core.Std
+
+module Monad = struct
+  type 'a t = 'a
+  let ( >>= ) v f = f v
+  let return = Fn.id
+  let protect = protect
+end
+
+(* Functor application, see revops_fn.ml *)
+include Revops_fn.Make(Monad)

          
A => src/revops/revops.mli +4 -0
@@ 0,0 1,4 @@ 
+(*
+ * Interface for reversible operations.
+ *)
+include Revops_intf.S with type 'a M.t = 'a

          
A => src/revops/revops_fn.ml +71 -0
@@ 0,0 1,71 @@ 
+(* Implementation for reversible operations. *)
+
+open Core.Std
+
+module Make = functor (Monad : Revops_intf.MONAD) -> struct
+  module M = Monad
+
+  module Oprev = struct
+    type 'a t = (unit -> 'a M.t) * ('a -> unit M.t)
+
+    let make do_fun undo_fun = (do_fun, undo_fun)
+  end
+
+  module Revop = struct
+    type 'a t = ('a * ('a -> unit M.t))
+  end
+
+  open M
+
+  let doop (do_fun, undo_fun) =
+    do_fun ()
+    >>= fun undo_state ->
+    return (undo_state, undo_fun)
+
+  let undo (undo_state, undo_fun) = undo_fun undo_state
+
+  let peek (undo_state, undo_fun) = undo_state
+
+  let compose ~introduce
+              ~eliminate_first
+              ~eliminate_second
+	      ~first
+	      ~second =
+  let (_, undo_first)  = first in
+  let (_, undo_second) = second in
+  let do_fun () =
+    doop first
+    >>= fun first_revop ->
+    doop second
+    >>= fun second_revop ->
+    introduce (peek first_revop) (peek second_revop)
+  in
+  let undo_fun undo_state =
+    eliminate_second undo_state
+    >>= fun second_state ->
+    undo_second second_state
+    >>= fun () ->
+    eliminate_first undo_state
+    >>= fun first_state ->
+    undo_first first_state
+  in
+  Oprev.make do_fun undo_fun
+
+  let compose_tuple first second =
+    compose
+      (fun l r -> return (l, r))
+      (Fn.compose return fst)
+      (Fn.compose return snd)
+      first
+      second
+
+  let ( +* ) = compose_tuple
+
+  let run_in_context oprev action =
+    doop oprev
+    >>= fun revop ->
+    let unit_action () = action (peek revop) in
+    M.protect
+      ~f:unit_action
+      ~finally:(fun () -> undo revop)
+end

          
A => src/revops/revops_fn.mli +7 -0
@@ 0,0 1,7 @@ 
+(*
+ * Interface for reversible operations.
+ *)
+
+module Make :
+  functor (Monad : Revops_intf.MONAD) ->
+    (Revops_intf.S with type 'a M.t = 'a Monad.t)

          
A => src/revops/revops_intf.ml +52 -0
@@ 0,0 1,52 @@ 
+module type MONAD = sig
+  type 'a t
+
+  val ( >>= ) : 'a t -> ('a -> 'b t) -> 'b t
+  val return : 'a -> 'a t
+  val protect : f:(unit -> 'a t) -> finally:(unit -> unit t) -> 'a t
+end
+
+module type S = sig
+  module M : MONAD
+
+  module Oprev : sig
+    type 'a t
+    val make : (unit -> 'a M.t) -> ('a -> unit M.t) -> 'a t
+  end
+
+  module Revop : sig
+    type 'a t
+  end
+
+  val doop : 'a Oprev.t -> 'a Revop.t M.t
+
+  val undo : 'a Revop.t -> unit M.t
+
+  val peek : 'a Revop.t -> 'a
+
+  (*
+   * Composes two oprevs. The order of evaluation on a doop of the result is the first
+   * oprev is setup and then the second. The order of evaluation on an undo is the
+   * second oprev is torn-down and then the first.
+   *)
+  val compose : introduce:('a -> 'b -> 'c M.t) ->
+                eliminate_first:('c -> 'a M.t) ->
+                eliminate_second:('c -> 'b M.t) ->
+                first:'a Oprev.t ->
+                second:'b Oprev.t ->
+                'c Oprev.t
+
+  val compose_tuple : 'a Oprev.t -> 'b Oprev.t -> ('a * 'b) Oprev.t
+
+  (* Infix shorthand for compose tuple. *)
+  val ( +* ) : 'a Oprev.t -> 'b Oprev.t -> ('a * 'b) Oprev.t
+
+  (*
+   * Runs a unit function in the context of an oprev.
+   * 1. doop the oprev.
+   * 2. Runs the unit function.
+   * 3. undo the revop.
+   * 4. Returns the value from the unit function.
+   *)
+  val run_in_context : 'a Oprev.t -> ('a -> 'b M.t) -> 'b M.t
+end

          
A => src/revops/revops_sys.ml +8 -0
@@ 0,0 1,8 @@ 
+(* Implementation of basic revops for system operations. *)
+
+open Core.Std
+
+let temp_file ?(prefix="Temp") ?(suffix = "CleanMe") () =
+  Revops.Oprev.make
+    (fun () -> Filename.temp_file prefix suffix)
+    (fun filename -> Unix.remove filename)

          
A => src/revops/revops_sys.mli +6 -0
@@ 0,0 1,6 @@ 
+(* Interface for basic revops for system operations. *)
+
+(*
+ * A revop for creating a temporary file and cleaning up afterward.
+ *)
+val temp_file : ?prefix:string -> ?suffix:string -> unit -> string Revops.Oprev.t

          
A => src/revops/revops_univ.ml +1 -0
@@ 0,0 1,1 @@ 
+include Revops_univ_fn.Make(Revops)

          
A => src/revops/revops_univ.mli +2 -0
@@ 0,0 1,2 @@ 
+(* Reversible operations using Univ_map as its state type. *)
+include Revops_univ_intf.S with type 'a R.Oprev.t = 'a Revops.Oprev.t

          
A => src/revops/revops_univ_fn.ml +30 -0
@@ 0,0 1,30 @@ 
+open Core.Std
+
+module Make = functor (Revops : Revops_intf.S) -> struct
+  module R = Revops
+
+  module M = Revops.M
+
+  module KeyOprev = struct
+    type 'a t = 'a Univ_map.Key.t * 'a Revops.Oprev.t
+  end
+
+  let noop =
+    Revops.Oprev.make
+      (Fn.const (M.return Univ_map.empty))
+      (Fn.const (M.return ()))
+
+  let extend first (key, oprev) =
+    let introduce map value = M.return (Univ_map.set map key value) in
+    let eliminate_second map = M.return (Univ_map.find_exn map key) in
+    Revops.compose
+      ~introduce
+      ~eliminate_first:M.return
+      ~eliminate_second
+      ~first
+      ~second:oprev
+
+  let ( +> ) = extend
+
+  let key name = Univ_map.Key.create ~name sexp_of_opaque
+end

          
A => src/revops/revops_univ_fn.mli +4 -0
@@ 0,0 1,4 @@ 
+(* Reversible operations using Univ_map as its state type. *)
+
+module Make : functor (Revops : Revops_intf.S) ->
+    (Revops_univ_intf.S with type 'a R.Oprev.t = 'a Revops.Oprev.t)

          
A => src/revops/revops_univ_intf.ml +25 -0
@@ 0,0 1,25 @@ 
+open Core.Std
+
+module type S = sig
+  module R : Revops_intf.S
+
+  module KeyOprev : sig
+    type 'a t = 'a Univ_map.Key.t * 'a R.Oprev.t
+  end
+
+  (* A Univ_map revop that does nothing. *)
+  val noop : Univ_map.t R.Oprev.t
+
+  (* Extend a Univ_map revop with a 'a Revop. *)
+  val extend : Univ_map.t R.Oprev.t ->
+               'a KeyOprev.t ->
+	       Univ_map.t R.Oprev.t
+
+  (* Infix operator version of extend. *)
+  val ( +> ) : Univ_map.t R.Oprev.t ->
+	       'a KeyOprev.t ->
+	       Univ_map.t R.Oprev.t
+
+  (* Creates a Univ_map.Key.t with the opaque serializer. *)
+  val key : string -> 'a Univ_map.Key.t
+end