Creating references to values and comparing references is all very jolly but the real reason to introduce references into the language is to enable the programmer to store values in a particular location for later retrieval and possible modification. Modification of the stored value is achieved by the use of the infix ``:='' assignment operator. For example, if n is an int ref then n := 1 and n := !n + 1 are legal assignments but we will never see n := n + 1.
The assignment operator has type ('a ref * 'a) -> unit. The result type of unit indicates that this operator achieves its effect by side-effect because we know in advance that the result returned by the function will be (). This value is needed for the result because an operator is only an infix function and all Standard ML functions must return some value, even if their purpose is to change the state.
Exercise
For the language designers, the other possible choice for the type of the assignment operator would be ('a ref * 'a) -> 'a. The effect of allowing this choice would be to allow the use of the value from an assignment. Define an infix operator ``::='' of type ('a ref * 'a) -> 'a which has this property. [Exercise care, there is a potential pitfall.]
The assignment operation genuinely increases the power of the language, as references did. We can now program call-by-need versions of the delay and force functions [*]. These variants are indistinguishable from the Susp.delay and Susp.force functions in the Standard ML library. These functions use references to an auxiliary datatype of suspended evaluations.
local datatype 'a hitchcock = mcguffin of unit -> 'a | corpse of 'a in abstype 'a susp = depalma of 'a hitchcock ref with fun delay f = depalma (ref (mcguffin f)) fun force (depalma (ref (corpse x))) = x | force (depalma (loc as ref (mcguffin f))) = let val c = f () in loc := corpse c; c end end end;