[MLton] broken attempt at encoding existentials

Stephen Weeks MLton@mlton.org
Fri, 23 Jan 2004 15:44:32 -0800


For the archives.  Here's a broken attempt at encoding an existential
type (a counter object) in SML.  It all works, except I can't figure
out how to make unpack generate a different type for each occurrence.
Hence, uses of unpack that should be rejected are accepted.

------------------------------------------------------------

signature COUNTER =
   sig
      type 'a obj = {create: 'a, get: 'a -> int, inc: 'a -> 'a}
      type t  (* exists 'a. 'a obj *)
      type 'a z
      val pack: 'a obj -> t
      val unpack: t * ('a z obj -> 'b) -> 'b
   end

functor TestCounter (Counter: COUNTER) =
   struct
      open Counter
	 
      val intC = pack {create = 1, get = fn i => i, inc = fn i => i + 1}
      val realC = pack {create = 1.0, get = Real.round, inc = fn r => r + 1.0}

      fun doit c = unpack (c, fn {create, get, inc} =>
			   print (concat [Int.toString (get (inc (inc create))),
					  "\n"]))
      val _ = doit intC
      val _ = doit realC

      (* This should be a type error! *)
      val _ = unpack (intC, fn {create, ...} =>
		      unpack (realC, fn {get, ...} => get create))
   end

structure Counter: COUNTER =
   struct
      type 'a obj = {create: 'a, get: 'a -> int, inc: 'a -> 'a}

      datatype t = T of exn obj

      type 'a z = exn

      fun 'a pack ({create, get, inc}: 'a obj) =
	 let
	    exception E of 'a
	    val create = E create
	    val get = fn E a => get a | _ => raise Fail "impossible"
	    val inc = fn E a => E (inc a) | _ => raise Fail "impossible"
	 in
	    T {create = create,
	       get = get,
	       inc = inc}
	 end
	 
      fun unpack (T r, f) = f r
   end

structure Test = TestCounter (Counter)