Introduction to standard ml

types in this form are, for the most part, superseded by the modules system described in the next chapter. 2.7. DEFINING TYPES 41 hidden from any program that uses the type (called a client): only the interface is available. Since programs written to use the type cannot tell what the implementation type is, they are restricted to using the functions provided by the interface of the type. Therefore the implementation can be changed at will, without a ecting the programs that use it. This is an important mechanism for structuring programs so as to prevent interference between components. Here is an example of an abstract type declaration. abstype color = blend of int*int*int with val white = blend(0,0,0) and red = blend(15,0,0) and blue = blend(0,15,0) and yellow = blend(0,0,15) fun mix(parts:int, blend(r,b,y), parts':int, blend(r',b',y')) = if parts<0 orelse parts'<0 then white else let val tp=parts+parts' and rp = (parts*r+parts'*r') div tp and bp = (parts*b+parts'*b') div tp and yp = (parts*y+parts'*y') div tp in blend(rp,bp,yp) end end; > type color val white = : color val red = : color val blue = : color val yellow = : color val mix = fn : int*color*int*color->color val green = mix(2, yellow, 1, blue); > val green = : color val black = mix(1, red, 2, mix(1, blue, 1, yellow)); > val black = : color There are several things to note about this declaration. First of all, the type equation occurring right after abstype is a data type declaration: exactly the same syntax applies, as the above example may suggest. Following 42 CHAPTER 2. THE CORE LANGUAGE the de nition of the implementation type is the interface declaration, between with and end. Examining ML's output for this declaration, we see that ML reports type color without an equation, re ecting the fact that it is a new type, unequal to any others. Furthermore, note that no constructors are declared as a result of the abstype declaration (unlike the case of data type de nitions). This prevents the client from building an object of type color by any means other than using one of the values provided by the interface of the type. These two facts guarantee that the client is insulated from the implementation details of the abstract type, and therefore allows for a greater degree of separation between client and implementor. Among other things, this allows for more exibility in program maintenance, as the implementation of color is free to be changed without a ecting the client. Note, however, that the functions de ned within the with clause do have access to the implementation type and its constructors, for otherwise the type would be quite useless! Note that the insulation of the client from the implementation of the abstract type prevents the client from de ning functions over that type by pattern matching. It also means that abstract types do not admit equality. If an abstract type is to support an equality test, then the implementor must de ne an equality function for it. Thus there are three ways to de ne type constructors in ML. Transparent type bindings are used to abbreviate complex type expressions, primarily for the sake of readability, rather than to introduce a new type. Data type bindings are used to extend the type system of ML. A data type is speci ed by declaring a new type constructor and providing a set of value constructors for that type. Data type de nitions are appropriate for specifying data that is described structurally (such as a tree), for then it is natural that the underlying structure be visible to the client. For data structures that are de ned behaviorally (such as a stack or a priority queue), an abstract type de nition is appropriate: the structural realization is not part of the de nition of the type, only the functions that realize the de ned behavior are relevant to the client. Exercise 2.7. 2 An abstract type set might be implemented by abstype 'a set = set of 'a list with val emptyset: 'a set = .