Rob,
The current saveState/loadState saves and restores the whole "state". It works at the level of the memory and has no knowledge of what the values represent. When you load "test2.polydb" this simply restores all global references to the values they had when you saved the state. In particular the global name space is restored so any declarations made after the save will be lost. Using a hierarchy doesn't change this behaviour; using child saved states merely reduces the amount of data that may need to be written out.

To change this behaviour the process of saving and restoring would need to be more closely integrated with ML itself. I think it would be possible to adapt the existing scheme so that instead of treating the global mutable values as roots the "save" operation would take a list of pointers and write out the data structure reachable from this, apart from any data in the parents. The corresponding "load" function would be passed these pointers once the data structures had been brought into memory. Using these operations as primitives it ought to be possible to write a "saveStructure" function that would look up an ML structure in the global state and write it out.
E.g.
structure S = struct val x = 1 end
PolyML.SaveState.saveStructure("S", "saveS.polydb", 1 (*Child level*));

The subsequently
PolyML.SaveState.loadStructure "saveS.polydb";
S.x;
Here "loadStructure" adds the structure declared within the saved state to the global name space. Unlike the existing "loadState" function it would know about the global name space.

There could be similar functions to save functors and signatures and, if necessary, types, values and fixity.

Since these saved modules would be relative to an existing executable and, possibly saved states, references to global types would match when the module was read in and there would be no need to package up type information explicitly. If a module referred to a type in a different module, though, the types would be different when the modules were read in.

I haven't thought this through in detail or made any experiments to check that it would all work but it seems feasible.

David

Rob Arthan wrote:
This may be obvious, but you don't need threads to exhibit this issue. E.g.,

val c1 = ref 1;

PolyML.SaveState.saveState "test1.polydb";  (* save state with c1 = ref 1 *)

val c2 = c1;
(c1 := 2; c2); (* val it = ref 2 *)

PolyML.SaveState.saveChild ("test2.polydb", 1); (* save state with c2 = c1 & c1 = ref 1 *)

val c3 = c1;
(c1 := 3; c3); (* val it = ref 2 *)

(* load the child test2.polydb *)
val c4 = (PolyML.SaveState.loadState "test2.polydb"; c3);

c1; (* val it = ref 2 *)
c4; (* val it = ref 3 *)
c3; (* Error-Value or constructor (c3) has not been declared *)

(c4 := 9; (c1, c4));(* val it = (ref 2, ref 9) *)
(c1 := 5; (c1, c4));(* val it = (ref 5, ref 9) *)

I would expect it to restore only that part of the state that is referred to by the child and that does not exist, if that makes sense. I would not have expected it to undeclare c3 above and would have expected it to leave c1, c2, c3 and c4 all referencing the same cell.

What would be very useful would be if you could save immediate children of some state (say each containing some data and some code to operate on that data) and load them in independently with any pointers into the common ancestry being resolved in the obvious way.

In ProofPower, for example, we currently have to save and reload the entire state of the theory hierarchy. It would be nice if theories and associated proof procedures could be saved separately and only loaded when needed. HOL IV has some kind of home-rolled way of achieving something that looks like this under Moscow ML (which effectively doesn't allow data to be saved at all, but does allow modules of code to be saved separately).
_______________________________________________
polyml mailing list
polyml@inf.ed.ac.uk
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml

Reply via email to