[MLton] SXML datatype definitions and the variables that use them

Matthew Fluet fluet@cs.cornell.edu
Thu, 15 Jun 2006 17:29:54 -0400 (EDT)


> My understanding of how datatype definitions are made is that they live in
> the top level Program structure and are simply a vector of Tycon.t * {con:
> Con.t * arg: Type.t option} vector each of which represents the definition
> of one datatype where {Con.t * Type.t option} a specific case (or arm) of
> that datatype.

Pretty much, although it is a record, rather than a tuple; from the 
SXML_TREE (= XML_TREE) signature, you can see that

       structure Program:
          sig
             datatype t =
                T of {body: Exp.t,
                      datatypes: {cons: {arg: Type.t option,
                                         con: Con.t} vector,
                                  tycon: Tycon.t,
                                  tyvars: Tyvar.t vector} vector,
                      (* overflow is SOME only after exceptions have been
                       * implemented.
                       *)
                      overflow: Var.t option}
             ...
          end

In the SXML intermediate language, the invariant is that 'tyvars' is 
always the empty vector.

> My question is if I construct a new datatype definition, for example,
>   datatype foo = A of unit | B of int
> and have a variable
>   val bar = A()
> How do I construct the type of bar?
>
> It seems logical that I would use Type.con and pass it the foo Tycon, but
> I'm unsure what the second argument (which is a vector of Type.t) does, or
> if this is even the correct thing to be doing.

The second argument is a vector of types to instantiate the type 
constructor; but, in SXML, there are no polymorphic type constructors, so 
pass the empty vector.

For example, in XML, if you wanted to construct the following:

   datatype 'a foo = A of unit | B of 'a
   val bar : int foo = A ()

you would do:

   open XmlTree
   val foo = Tycon.newString "foo"
   val a = Tyvar.newNoname {equality = false}
   val A = Con.newString "A"
   val B = Con.newString "B"
   val fooDT = {cons = Vector.new2
                       ({arg = SOME (Type.unit)},
                         con = A},
                        {arg = SOME (Type.var a),
                         con = B}),
                tycon = foo,
                tyvars = Vector.new1 (a)}
   val u = Var.newString "u"
   val uDec = Dec.MonoVal
              {exp = PrimApp.Tuple (Vector.new0 ()),
               ty = Type.unit,
               var = u}
   val bar = Var.newString "bar"
   val typeVec = Vector.new1 (Type.defaultWord)
   val barDec = Dec.MonoVal
                {exp = PrimApp.ConApp
                       {arg = u,
                        con = A,
                        targs = typeVec},
                 ty = Type.con (foo, typeVec),
                 var = bar}

In SXML, the datatype and variables must be monomorphic; so, if you wanted 
to construct the following:

   datatype foo = A of unit | B of int
   val bar : foo = A ()

you would do:

   open SxmlTree
   val foo = Tycon.newString "foo"
   val A = Con.newString "A"
   val B = Con.newString "B"
   val fooDT = {cons = Vector.new2
                       ({arg = SOME (Type.unit)},
                         con = A},
                        {arg = SOME (Type.defaultWord),
                         con = B}),
                tycon = foo,
                tyvars = Vector.new0 ()}
   val u = Var.newString "u"
   val uDec = Dec.MonoVal
              {exp = PrimApp.Tuple (Vector.new0 ()),
               ty = Type.unit,
               var = u}
   val bar = Var.newString "bar"
   val barDec = Dec.MonoVal
                {exp = PrimApp.ConApp
                       {arg = u,
                        con = A,
                        targs = Vector.new0 ()},
                 ty = Type.con (foo, Vector.new0 ()),
                 var = bar}