Chapter 2: The Standard ML Initial Basis

This chapter describes the Initial Basis as implemented in the original 1990 definition of Standard ML.  It has largely been superseded by the Standard Basis Library which provides a much fuller set of functions.  The functions in this chapter are still available in the SML90 structure but where possible the Standard Basis Library should be used.

The ML Standard requires that any implementation should provide a small, standard, initial environment, called the Initial Basis. This chapter documents the Initial Basis, as provided by Poly/ML, except for the I/O functions which are dealt with in the next chapter.

2.1 Types

The following types are predefined by the Standard:

datatype bool of true | false
datatype 'a list of nil | :: of 'a * 'a list
eqtype string
eqtype int
eqtype real
eqtype 'a ref
type exn
type instream
type outstream

Note: exception constructors, declared using exception, produce values of type exn.

2.2 Infixes

The Standard predefines the following fixities:

infix 7 * div mod /
infix 6 + - ^
infix 5 :: @
infix 4 = <> < <= >= <
infix 3 := o

Any of these may be changed by a user fixity directive, but doing this would probably be unwise.

2.3 Boolean and Comparison Functions

datatype bool = true | false
val not : bool -> bool
val = : ''a * ''a -> bool
val <> : ''a * ''a -> bool

not b returns the negation of b. This function behaves as if it were defined by:

fun not true = false
  | not false = true;

x = y returns true if x and y are equal and false otherwise. For refs and non-empty arrays two objects are equal only if they were created by the same function call. For other objects, equality is structural - two objects are equal if they have equal subparts.

x <> y is equivalent to not (x = y).

Note 1: the equality type variable ''a which occurs in the type of = and <> ensures that the use of these functions is restricted to equality types. Roughly speaking, an object belongs to an equality type if it doesn't contain any functions or abstypes.

Note 2: Standard ML does not provide standard functions for and and or; it provides andalso and orelse keywords instead. These keywords provide shortcut (left-to-right) evaluation of the corresponding boolean operations.

2.4 Integers and Reals

2.4.1 Type conversion

Standard ML provides arithmetic operations on the two distinct types int and real.

eqtype int
eqtype real

exception Floor
val floor : real -> int

exception Real (* NONSTANDARD *)
val real : int -> real

The functions floor and real convert between the two types real and int.

floor r is the largest integer which is not greater than the real number r.

real i is the real number corresponding to the integer i.

Note 1: the Standard specifies that the exception Floor is raised whenever the result of the floor operation won't fit into an integer. Since Poly/ML uses arbitrary-precision integers, this never occurs. Some other implementations of Standard ML use finite-precision arithmetic so a fully portable program must still be prepared to handle Floor.

Note 2: the Real exception is not part of the ML Standard, which assumes that any int can be converted into a real; with arbitrary-precision integers and IEEE standard reals, this is not a reasonable assumption. The Poly/ML implementation of real will raise the non-standard exception Real if the integer is too large to convert.

2.4.2 Arithmetic functions

These operations provide standard arithmetic operations on int and real. Note that most of these operations are overloaded; if you use them, you must provide enough type information so that the compiler can determine which version you want.

exception Neg
val ~ : int -> int
val ~ : real -> real

exception Abs
val abs : int -> int
val abs : real -> real

exception Sum
val + : int * int -> int
val + : real * real -> real

exception Diff
val - : int * int -> int
val - : real * real -> real

exception Prod
val * : int * int -> int
val * : real * real -> real

exception Div
val div : int * int -> int

exception Mod
val mod : int * int -> int

exception Quot
val / : real * real -> real

Note 1: the above exceptions are raised when the result of the corresponding function is too large. Since Poly/ML uses arbitrary-precision integers (and since a real can always be negated), the exceptions Neg and Abs will never be raised and the exceptions Sum, Diff and Prod will not be raised by the integer versions of the functions. The exceptions Div and Mod will be raised only for division by zero. Programs which are written for portability should still handle these exceptions, however, as some other implementations of Standard ML use finite-precision arithmetic.

Note 2: the operators mod and div are defined so that the remainder has the same sign as the divisor. For example:

20 mod  7 = 6
~20 mod ~7 = ~6
20 mod ~7 = ~l
~20 mod  7 = 1
20 div   7 = 2
~20 div ~7 = 2
20 div ~7 = ~3
~20 div  7 = ~3

2.4.3 Trigonometric functions

val sin : real -> real
val cos : real -> real
val arctan : real -> real

exception Exp
val exp : real -> real

exception Ln
val ln : real -> real

exception Sqrt
val sqrt : real -> real

These are the standard mathematical functions; if the argument is outside the domain of the function or if the result is too large to represent then the corresponding exception will be raised.

2.4.4 Order Relations

Standard ML provides the usual ordering tests on integers and reals.

val < : int * int -> bool
val < : real * real -> bool

val <= : int * int -> bool
val <= : real * real -> bool

val >= : int * int -> bool
val >= : real * real -> bool

val > : int * int -> bool
val > : real * real -> bool

As for the arithmetic operations, these are overloaded so the compiler must be given enough type information to disambiguate them.

2.5 List processing

Standard ML provides a few built-in functions for list processing:

datatype 'a list nil | :: of 'a * 'a list
val @ : 'a list 'a list -> 'a list
val rev : 'a list -> 'a list
val map ('a -> 'b) -> 'a list -> 'b list

These behave as if they were defined as follows:

fun nil @ l = l
| (h :: t) @ l = h :: (t @ l);

fun map f nil = nil
| map f (h :: t) = f h :: map f t;

local
  fun revOnto l nil = l
    | revOnto l (h :: t) = revOnto (h :: l) t
in
  fun rev l = revOnto nil l
end;

2.6 String processing

Standard ML also provides a few built-in functions for string processing:

eqtype string
val size : string -> int

exception Ord
val ord : string -> int

exception Chr
val chr : int -> string

val explode : string -> string list
val implode : string list -> string
val ^ : string * string -> string

size s returns the length of the string s, in characters.

ord s returns the ASCII code of the first character of the string s. It raises the exception Ord if the string is empty.

chr i returns a one-character string consisting of the character whose ASCII code is i. It raises the exception Chr if i is not in the range 0 < i < 256.

explode s converts the string s into a list of one-character strings - one string for each character of the original string s.

implode sl concatenates all the strings in the string-list sl.

s1 ^ s2 coneatenates the two strings s1 and s2.

Poly/ML overloads the relational operators <, <=, >= and > so that they also operate on strings (in addition to ints and reals), using lexicographic ordering.

val < : string * string -> bool
val <= : string * string -> bool
val >= : string * string -> bool
val > : string * string -> bool

The provision of relational operators on strings is a non-standard extension to the Standard Initial Basis and may not be supported by other implementations of Standard ML.

2.7 Refs

Standard ML provides a collection of operations on the type ref.

eqtype 'a ref
val ref: '_a -> '_a ref
val := : 'a ref * 'a -> unit
val ! : 'a ref -> 'a

ref x creates a new ref (updatable pointer) to x.

r : = x updates the ref r so that it now points to the value x.

! r returns the value which is currently pointed at by the ref r.

Note 1: the value constructor ref may also be used in patterns, so that could be defined as follows:

fun ! (ref x) = x;

Note 2: 'a ref is an equality type even if 'a isn't; no other type constructor has this property. This means that it is always possible to compare two refs (of the same type) for equality even if we can't compare the objects they refer to. Two refs are equal precisely when they are, in fact, the same ref; the referenced objects are not tested for equality.

2.8 Miscellaneous

This section describes those parts of the Initial Basis that don't fit elsewhere.

val o : ('b -> 'c) * ('a -> 'b) -> ('a -'c)

The infix function o implements function composition; it behaves as if it were defined as follows:

fun (f o g) x = f (g x);

exception Match
exception Bind
exception Interrupt

Match is raised whenever a non-exhaustive pattern match in a fun, fn or case expression fails to find a clause which matches the selection expression.

Bind is raised whenever ML attempts to bind an expression to a pattern that doesn't match it (in a let or local declaration).

Interrupt is raised when Poly/ML is interrupted, either externally (by <control-C> f) or internally (by running out of heap space).

Note: the ML Standard requires the compiler to warn the programmer about any non-exhaustive matches which might allow the exceptions Match and Bind to be raised.

Copyright (c) 2000 CUTS and contributers.  Last updated: 15 January 2002 by David Matthews.