Previous Up Next

4  Type checking

MLton's type checker follows the Definition of SML closely, so you may find differences between MLton and other SML compilers that do not follow the Definition so closely. In particular, SML/NJ has many deviations from the Definition -- please see Appendix A for a list of those that we are aware of.

In some respects MLton's type checker is more powerful than other SML compilers, so there are programs that MLton accepts that are rejected by some other SML compilers. These kinds of programs fall into a few simple categories.

4.1  Type error messages

To aid in the understanding of type errors, MLton's type checker displays type errors differently than other SML compilers. In particular, when two types are different, it is important for the programmer to easily understand why they are different. So, MLton displays only the differences between two types that don't match, using underscores for the parts that do. For example, if a function expects real * int but gets real * real, the type error message would look like
expects: _ * [int]
but got: _ * [real]
As another aid to spotting differences, MLton places brackets [] around the parts of the types that don't match. A common situation is when a function receives a different number of arguments than it expects, in which case you might see an error like
expects: [int * real]
but got: [int * real * string]
The brackets make it easy to see that the problem is that the tuples have different numbers of components -- not that the components don't match. Contrast that with a case where a function receives the right number of arguments, but in the wrong order.
expects: [int] * [real]
but got: [real] * [int]
Here the brackets make it easy to see that the components do not match.

MLton's type checker is fairly new. If you encounter a difference between MLton and another SML compiler, or even with an older version of MLton, and are not able to determine if it is a bug, please send mail to MLton@mlton.org. We would also appreciate feedback on any type error messages that you find confusing, or suggestions you may have for improvements to error messages.

4.2  Type information about programs

MLton has a flag, -show-basis file, that causes MLton to pretty print to file the basis defined by the input program. For example, if foo.sml contains
fun f x = x + 1
then mlton -show-basis foo.basis foo.sml will create foo.basis with the following contents.
val f: int -> int
If you only want to see the basis and do not wish to compile the program, you can call MLton with -stop tc.

When displaying signatures, MLton prefixes types defined in the signature them with ?. to distinguish them from types defined in the environment. For example,
signature SIG =
   sig
      type t
      val x: t * int -> unit
   end
is displayed as
signature SIG = 
   sig
      type t = ?.t
      val x: (?.t * int) -> unit
   end
Notice that int occurs without the ?. prefix.

MLton also uses a canonical name for each type in the signature, and that name is used everywhere for that type, no matter what the input signature looked like. For example
signature SIG =
   sig
      type t
      type u = t
      val x: t
      val y: u
   end
is displayed as
signature SIG = 
   sig
      type t = ?.t
      type u = ?.t
      val x: ?.t
      val y: ?.t
   end
Canonical names are always relative to the ``top'' of the signature, even when used in nested substructures. For example,
signature S =
   sig
      type t
      val w: t
      structure U:
         sig
            type u
            val x: t
            val y: u
         end
      val z: U.u
   end
is displayed as
signature S = 
   sig
      type t = ?.t
      val w: ?.t
      val z: ?.U.u
      structure U:
         sig
            type u = ?.U.u
            val x: ?.t
            val y: ?.U.u
         end
   end
When displaying structures, MLton uses signature contstraints wherever possible, combined with where type clauses to specify the meanings of the types defined within the signature.
signature SIG =
   sig
      type t
      val x: t
   end
structure S: SIG =
   struct
      type t = int
      val x = 13
   end
structure S2:> SIG = S
is displayed as
structure S: SIG
             where type t = int
structure S2: SIG
              where type t = S2.t
signature SIG = 
   sig
      type t = ?.t
      val x: ?.t
   end

Previous Up Next