Home Announce Handouts Slides Reading People Office Hours
 

Review Session Summary (October 17)
Handout #9

1. Running the SML compiler

It is difficult to get acquainted with a language without getting a feel of it on a real working system. Thus, the first thing we discussed was a quick introduction to the SML-NJ compiler installed on the Leland machines. A simple sml command starts the compiler, and some simple operations (loading from files, setting printDepth etc) were pointed out. The details are available at the SML-NJ homepage , along with tutorials and extensive documentation.

If you would like to download the ML compiler, follow the links from our programming page.

2. ML programming

A typical ML programming example was considered to familiarise with the syntax and user-defined types. For this purpose, a list datatype was developed and a simple function was designed to act on that datatype.

The ourlist datatype was defined as:

       datatype 'a ourlist = nil | LIST of 'a * 'a ourlist;

The meaning of a recursive datatype was discussed, and also the idea of a type parameter as represented by 'a. The usage of LIST (and other such tags) in disjoint union types was particularly confusing to students. It was easier for some students to understand it in terms of a constructor of the ourlist datatype, just like the cons used in Lisp.

To illustrate the ideas of pattern matching, we developed a simple function that works on the ourlist type just defined. The example taken was to define a count function that takes in a value and a list, and counts the number of occurences of that value in the list. Thus the intended semantics of the count function should allow a call such as the following to work:

       - count (1, LIST(2,LIST(1, LIST(1, nil))));
       val it = 2 : int

In essence, the above count function call should count the number of occurences of 1 in the list containing the members 2, 1, 1.

Since we expect to compare the first argument with the members of the list, the expected type of the count function is:

       val count = fn : ''a * ''a ourlist -> int

Then we went ahead and developed the ML code for the count function, using the obvious recursive idea of breaking a list into a head and an attached list. The ML pattern matching system was displayed here, and the required exhaustive nature of the patterns was pointed out. The final code for the count function designed is given below.

       fun count (x,nil) = 0 |
           count (x,LIST(y,z)) = if (x=y) then (1+(count (x,z))) else count (x,z);

3. Type inference in ML

We went over the basic type inference system in ML, both at an intuitive level and at an algorithmic level using parse graphs.

To start, the construction of parse graphs was shown by parsing the given ML function as a lambda expression. It was shown that constructing the parse graph bottom upwards seemed to be more intuitive, especially when the final graph was large and deep.

The procedure of type inference was sketched out. The idea of overloaded functions and the difference between overloading and true parametric polymorphism was demonstrated using the + operator as an example. Overloaded functions have different code for different argument types, and the compiler must be able to figure out the code version to use at compile time.

The examples used to illustrate type inference were mainly from the book, and it would not be worth the effort to repeat the graphical solutions here. The interested student is referred to the examples given in the course text.


Rajat Raina
October 21, 2002