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

Harvey Mudd College
Computer Science 131
Programming Languages
Spring Semester 2000

Lecture 20a

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

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

The creators of SML realized that there were some times when programming in the traditional imperative way, with updates, is a lot simpler. So, now I want to talk about the question of how to get variable names whose values we can change when we really really really feel we need them.

The way you do this in SML is by the ref type, which really amounts to an explicit pointer.

To construct such a cell use the ref constructor:

val x = ref 3;
To update the value of the cell, you use the update operator:
x := 4;
To explicitly dereference the pointer and get the value at the end of it, you use the bang (!) operator. Compare the results of:
x;
!x;

Now, consider:

val j = 5;
val j1 = ref 5;

fun add_j k = j + k; fun add_j1 k = !j1 + k;

add_j 3; add_j1 3;

val j = 7; j1 := 7;

add_j 3; add_j1 3;

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

A common use of refs is to provide the functionality of static variables in C:

local 
   val count = ref 0
in 
   fun foo () = (
                 count := !count + 1 ;
                 !count
                )
end;

We can extend this program to allow the starting value to come in as a parameter by building the function on the fly and returning it:

fun new_counter start =
   let
      val count = ref start
   in 
      fn () => (
                count := !count + 1 ;
                !count
               )
   end;

Similarly, we could create a linear congruential pseudo-random number generator as follows:

local 
   val multiplier = 25173
   val increment = 13849
   val modulus  = 32768
in
   fun newRandom seed = 
      let
         val current = ref seed
      in 
         fn range => (
                      current := ((!current * multiplier) + 
                                  increment) mod modulus ;
                      !current mod range
                     )
      end
end;

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

We can take this idea a step further and even get a notion of object with mutable state.

exception IllegalAction;

fun mkCounter () =
      let
         val counter = ref 0
      in
         fn "Val" => !counter
          | "Inc" => (
                    counter := !counter + 1;
                    !counter
                   )
          | "Dec" => (
                    counter := !counter - 1;
                    !counter
                   )
          | "Reset" => (
                    counter := 0;
                    !counter
                   )
          | _ => raise IllegalAction
      end;

Actually, it would be more typical to encode the messages in a new enumerated type, as in:


datatype counterMessage = Val | Inc | Dec | Reset;

fun mkCounter () =
      let
         val counter = ref 0
      in
         fn Val => !counter
          | Inc => (
                    counter := !counter + 1;
                    !counter
                   )
          | Dec => (
                    counter := !counter - 1;
                    !counter
                   )
          | Reset => (
                    counter := 0;
                    !counter
                   )
      end;

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

One potential problem with refs is that if you are not careful, they open a potential hole in the ML type system.

Consider the declaration:

val x = ref (fn x => x);
What is the type of x?

Then what do we make of the following expression:

(x := (fn x => x + 1);
!x true)
Each part is correctly typed, yet they cannot be combined into a single typable expression.

For this reason, SML restricts refs to being built essentially on monomorphic values. That is, in general you must know their precise type at the time you create them. The type must be known before the ref is created.

The restriction extends up to structures and functions built from refs. So, the function:

fun f x = ref [x];
is legal, but cannot be applied to nil.

This restriction gives rise to the general ``value type restriction'' that we have discussed earlier, and which has plagued us occasionally. For a full description see


http://cm.bell-labs.com/cm/cs/what/smlnj/doc/Conversion/types.html

------------------------
This page copyright ©1999 by Joshua S. Hodas. It was built on a Macintosh. Last rebuilt on Tuesday, February 9, 1999 at 2:39:10 PM.
http://cs.hmc.edu/~hodas/courses/cs131/lectures/lecture06s.html