type Counter = {get : unit -> int, inc : unit -> int};

val c : Counter =
    let val x = ref 1 
     in
	{get = fn _ => !x,
	 inc = fn _ => (x := !x+1; !x)}
    end;

val inc3 : Counter -> int =
    fn c => (#inc c(); #inc c(); #inc c(); #get c());

val 4 = inc3 c;
val 7 = inc3 c;

val newCounter : unit -> Counter =
    fn _ =>
    let val x = ref 1 
     in
	{get = fn _ => !x,
	 inc = fn _ => (x := !x+1; !x)}
    end;

type ResetCounter =
     {get : unit -> int,
      inc : unit -> int,
      reset : unit -> unit};

val newResetCounter : unit -> ResetCounter =
    fn _ =>
    let val x = ref 1 
     in
	{get = fn _ => !x,
	 inc = fn _ => (x := !x+1; !x),
	 reset = fn _ => x := 1}
    end;

type CounterRep = {x:int ref}

val counterClass : CounterRep -> Counter =
    fn r => {get = fn _ => ! (#x(r)),
             inc = fn _ => (#x(r) := ! (#x(r))+1; !(#x(r)))};

val newCounter : unit -> Counter =
    fn _ => let val r = {x = ref 1} in counterClass r end;

val resetCounterClass : CounterRep -> ResetCounter =
    fn r => let
	      val super = counterClass r
	    in
	      {get = #get(super),
	       inc = #inc(super),
	       reset = fn _ => #x(r) := 1}
	    end;

type BackupCounterRep = {x:int ref, b:int ref};
type BackupCounter =
     {get : unit -> int,
      inc : unit -> int,
      reset : unit -> unit,
      backup : unit -> unit};

val backupCounterClass : BackupCounterRep -> BackupCounter =
    fn r => let
              (* coerce explicitly because SML lacks subtyping:
	         resetCounterClass r would give an error
	      *)
	      val super = resetCounterClass {x = #x(r)}
	    in
	      {get = #get(super),
	       inc = #inc(super),
	       reset = fn _ => (#x(r) := !(#b(r))),
	       backup = fn _ => (#b(r) := !(#x(r)))}
	    end;

val newBackupCounter : unit -> BackupCounter =
    fn _ => let
	      val r = {x = ref 1, b = ref 1}
	    in
	      backupCounterClass r
	    end;

val b = newBackupCounter ();
val 3 = (#inc(b)(); #inc(b)(); #backup(b)();
	 #inc(b)(); #reset(b)(); #get(b)());
