This chapter describes the standard initial top-level environment, that is, those identifiers available unqualified before the user introduces additional top-level bindings. As special aspects of this environment, infix identifiers and overloading are also discussed.
There are two reasons for including (non-module) identifiers in the top-level environment. The first is convenience. Certain types and values are used so frequently that it would be perverse to force the programmer to always open the containing structures or to use the qualified names. This is particularly true for interactive interfaces, in which notational simplicity and fewer keystrokes are desirable. The second reason is to allow operator overloading.
There are no default requirements on which modules will be initially available at top-level for either interactive or batch-oriented sessions. Each implementation may provide its own mechanism for making its various modules available to the user's code. Even the presence of a top-level identifier that is logically defined in a structure (e.g., the type int
is defined in the Int
structure) is no guarantee that the structure name is in the environment.
Various types, exceptions, and values are available in the top-level environment without qualification. In particular, everything in the General
structure is available.
We note that the special identifiers =
and <>
, corresponding to polymorphic equality and inequality, are available in the top-level environment but are not bound in any module.
[FLOAT] presents the top-level types and their defining structures, if any.
eqtype unit
|
General
|
eqtype int
|
Int
|
eqtype word
|
Word
|
type real
|
Real
|
eqtype char
|
Char
|
eqtype string
|
String
|
type substring
|
Substring
|
type exn
|
General
|
eqtype 'a array
|
Array
|
eqtype 'a vector
|
Vector
|
eqtype 'a ref
| primitive |
datatype bool = false | true
| primitive |
datatype 'a option = NONE | SOME of 'a
|
Option
|
datatype order = LESS | EQUAL | GREATER
|
General
|
datatype 'a list = nil | :: of ('a * 'a list)
| primitive |
Although the types bool
and list
are considered primitive and defined in the top-level environment, for consistency they are also bound in the structures Bool
and List
, respectively.
The next list presents the exception constructors available at top-level. All of these are defined in the General
structure, except for Option
, which is defined in the Option
structure, and Empty
, which is defined in the List
structure.
exception Bind
|
exception Chr
|
exception Div
|
exception Domain
|
exception Empty
|
exception Fail of string
|
exception Match
|
exception Option
|
exception Overflow
|
exception Size
|
exception Span
|
exception Subscript
|
The next table presents the non-overloaded functions available at top-level, plus the structure value to which each is bound. Note that the use
function is special. Although not defined precisely, its intended purpose is to take the pathname of a file and treat the contents of the file as SML source code typed in by the user. It can be used as a simple build mechanism, especially for interactive sessions. Most implementations will provide a more sophisticated build mechanism for larger collections of source files. Implementations are not required to supply a use
function.
val ! : 'a ref -> 'a
|
General.!
|
val := : 'a ref * 'a -> unit
|
General.:=
|
val @ : ('a list * 'a list) -> 'a list
|
List.@
|
val ^ : string * string -> string
|
String.^
|
val app : ('a -> unit) -> 'a list -> unit
|
List.app
|
val before : 'a * unit -> 'a
|
General.before
|
val ceil : real -> int
|
Real.ceil
|
val chr : int -> char
|
Char.chr
|
val concat : string list -> string
|
String.concat
|
val exnMessage : exn -> string
|
General.exnMessage
|
val exnName : exn -> string
|
General.exnName
|
val explode : string -> char list
|
String.explode
|
val floor : real -> int
|
Real.floor
|
val foldl : ('a*'b->'b)-> 'b -> 'a list -> 'b
|
List.foldl
|
val foldr : ('a*'b->'b)-> 'b -> 'a list -> 'b
|
List.foldr
|
val getOpt : ('a option * 'a) -> 'a
|
Option.getOpt
|
val hd : 'a list -> 'a
|
List.hd
|
val ignore : 'a -> unit
|
General.ignore
|
val implode : char list -> string
|
String.implode
|
val isSome : 'a option -> bool
|
Option.isSome
|
val length : 'a list -> int
|
List.length
|
val map : ('a -> 'b) -> 'a list -> 'b list
|
List.map
|
val not : bool -> bool
|
Bool.not
|
val null : 'a list -> bool
|
List.null
|
val o : ('a->'b) * ('c->'a) -> 'c->'b
|
General.o
|
val ord : char -> int
|
Char.ord
|
val print : string -> unit
|
TextIO.print
|
val real : int -> real
|
Real.fromInt
|
val ref : 'a -> 'a ref
| primitive |
val rev : 'a list -> 'a list
|
List.rev
|
val round : real -> int
|
Real.round
|
val size : string -> int
|
String.size
|
val str : char -> string
|
String.str
|
val substring : string * int * int -> string
|
String.substring
|
val tl : 'a list -> 'a list
|
List.tl
|
val trunc : real -> int
|
Real.trunc
|
val use : string -> unit
| implementation dependent |
val valOf : 'a option -> 'a
|
Option.valOf
|
val vector : 'a list -> 'a vector
|
Vector.fromList
|
The SML Standard Basis includes a fixed set of overloaded identifiers; programmers may not define new overloadings. These identifiers, with their type schemas and default types, are:
val + : num * num -> num
|
int * int -> int
|
val - : num * num -> num
|
int * int -> int
|
val * : num * num -> num
|
int * int -> int
|
val div : wordint * wordint -> wordint
|
int * int -> int
|
val mod : wordint * wordint -> wordint
|
int * int -> int
|
val / : real * real -> real
|
real * real -> real
|
val ~ : num -> num
|
int -> int
|
val abs : realint -> realint
|
int -> int
|
val < : numtext * numtext -> bool
|
int * int -> bool
|
val > : numtext * numtext -> bool
|
int * int -> bool
|
val <= : numtext * numtext -> bool
|
int * int -> bool
|
val >= : numtext * numtext -> bool
|
int * int -> bool
|
= {FixedInt.int, Int.int, Int<N>.int
, IntInf.int, LargeInt.int, Position.int}
= {LargeWord.word, Word.word, Word8.word, Word<N>.word
, SysWord.word}
= {LargeReal.real, Real.real, Real<N>.real
}
= {String.string, Char.char, WideString.string, WideChar.char}
=
word union int
=
real union int
=
word union int union real
=
num union text
abs
cannot have type int -> real
, but only a type like int -> int
. In addition, we note that Int<N>.int
, IntInf.int
, Word<N>.word
, Real<N>.real
, WideString.string
, and WideChar.char
are optional types.
The function identifiers have a default type that is adopted in lieu of any type information supplied by the surrounding context. All overloaded value identifiers default to an int
-based type except for the operator /
, whose default type is real * real -> real
. Thus, the following code would typecheck:
fun f(x,y) = x <= y val x = (1 : LargeInt.int) val y = x + 1 fun g x = x + x before ignore (x + 0w0)with
f
, y
, and g
having types int * int -> bool
, LargeInt.int
, and word -> word
, respectively.
The top-level environment has the following infix identifiers:
infix 7 * / div mod infix 6 + - ^ infixr 5 :: @ infix 4 = <> > >= < <= infix 3 := o infix 0 beforeThe digit in each row gives the precedence (binding power) of each identifier, so that
+
and -
bind equally tightly, and both bind more tightly than ::
and @
. All these identifiers are left-associative (bind more tightly to the left) except ::
and @
, which are right-associative.
The Basis Library specifies very little about the operating system environment in which SML programs are executed. This gives implementations the widest possible freedom. Programs may be executed as part of an interactive session, as stand-alone executables, or as server processes.
There are a few points, however, where the surrounding environment does impinge on the Basis Library. We summarize these points here.
The CommandLine
structure defines functions that return the name and arguments with which a program was invoked. The method for setting these values is entirely up to the implementation. We would expect that if a stand-alone executable is run from a command line, then these values would be determined from the name and arguments specified on that command line.
Implementations may provide a mechanism for taking a function and producing a stand-alone executable. If such a mechanism is provided, the type of the function being exported must be
(string * string list) -> OS.Process.statusWhen the stand-alone executable is invoked, the function should be called with a first argument equal to
CommandLine.name ()
and a second argument equal to CommandLine.arguments ()
.
The OS.Process.getEnv
function assumes that the environment associates a set of name-value pairs with the invocation of a program, where both name and value are strings. This function returns the value associated with the given name. This is essentially a mechanism for providing global variables, by which the user can provide values that can be used deep within a program. The method for specifying this set is OS-dependent. The set may be empty.
The OS.Process.exit
and OS.Process.terminate
functions return a status value to the environment. The type of this value, and how the environment interprets it, is OS-dependent.
The OS.Process.atExit
function adds an argument function to the actions that are executed when the program reaches a normal termination. A normal termination is a call to OS.Process.exit
, or as defined by the implementation. If a stand-alone executable is created from a function as above, then normal termination occurs when that function returns. We would expect other methods for creating stand-alone executables to behave similarly.
Abnormal terminations include calls to OS.Process.terminate
, or when a stand-alone executable does not handle a raised exception. The functions registered by OS.Process.atExit
are not evaluated in the event of an abnormal program termination.
Some actions are implicitly registered with OS.Process.atExit
, so that they always occur on a normal program termination. These must include the flushing and closing of all open output streams created by the open functions in BinIO
and TextIO
, and the flushing (but not closing) of TextIO.stdOut
and TextIO.stdErr
. Although this covers most usual cases, for maximum portability and robustness, code should flush streams explicitly.
Generated April 12, 2004
Last Modified October 4, 1997
Comments to John Reppy.
This document may be distributed freely over the internet as long as the copyright notice and license terms below are prominently displayed within every machine-readable copy.
Copyright © 2004 AT&T and Lucent Technologies. All rights reserved.
Permission is granted for internet users to make one paper copy for their
own personal use. Further hardcopy reproduction is strictly prohibited.
Permission to distribute the HTML document electronically on any medium
other than the internet must be requested from the copyright holders by
contacting the editors.
Printed versions of the SML Basis Manual are available from Cambridge
University Press.
To order, please visit
www.cup.org (North America) or
www.cup.cam.ac.uk (outside North America). |