Sample Code for this Chapter

Standard ML Basis Library defines a three-layer input and output facility for Standard ML.   These modules provide a rudimentary, platform-independent text I/O facility that we summarize briefly here.  The reader is referred to the IO section of the Standard ML Basis Library for more details.  There is no standard library for graphical user interfaces; each implementation provides its own package.  See your vendor's documentation for details.

The text I/O primitives are based on the notions of an input stream and an output stream, which are values of type instream and outstream, respectively.  An input stream is an unbounded sequence of characters arising from some source.  The source could be a disk file, an interactive user, or another program (to name a few choices).  Any source of characters can be attached to an input stream.  An input stream may be thought of as a buffer containing zero or more characters that have already been read from the source, together with a means of requesting more input from the source should the program require it.  Similarly, an output stream is an unbounded sequence of characters leading to some sink.  The sink could be a disk file, an interactive user, or another program (to name a few choices).  Any sink for characters can be attached to an output stream.  An output stream may be thought of as a buffer containing zero or more characters that have been produced by the program but have yet to be flushed to the sink.

Each program comes with one input stream and one output stream, called stdIn and stdOut, respectively. These are ordinarily connected to the user's keyboard and screen, and are used for performing simple text I/O in a program.  The output stream stdErr is also pre-defined, and is used for error reporting.   It is ordinarily connected to the user's screen.

Textual input and output are performed on streams using a variety of primitives.   The simplest are inputLine and print.  To read a line of input from a stream, use the function inputLine of type instream -> string.  It reads a line of input from the given stream and yields that line as a string whose last character is the line terminator.  If the source is exhausted, return the empty string.  To write a line to stdOut, use the function print of type string -> unit.  To write to a specific stream, use the function output of type outstream * string -> unit, which writes the given string to the specified output stream.  For interactive applications it is often important to ensure that the output stream is flushed to the sink (e.g., so that it is displayed on the screen).  This is achieved by calling flushOut of type outstream -> unit, which ensures that the output stream is flushed to the sink.  The print function is a composition of output (to stdOut) and flushOut.

A new input stream may be created by calling the function openIn of type string -> instream.  When applied to a string, the system attempts to open a file with that name (according to operating system-specific naming conventions) and attaches it as a source to a new input stream.  Similarly, a new output stream may be created by calling the function openOut of type string -> outstream.   When applied to a string, the system attempts to create a file with that name (according to operating system-specific naming conventions) and attaches it as a sink for a new output stream.  An input stream may be closed using the function closeIn of type instream -> unit.  A closed input stream behaves as if there is no further input available; request for input from a closed input stream yield the empty string.  An output stream may be closed using closeOut of type outstream -> unit.  A closed output stream is unavailable for further output; an attempt to write to a closed output stream raises the exception TextIO.IO.

The function input of type instream -> string is a blocking read operation that returns a string consisting of the characters currently available from the source.  If none are currently available, but the end of source has not been reached, then the operation blocks until at least one character is available from the source.  If the source is exhausted or the input stream is closed, input returns the null string.  To test whether an input operation would block, use the function canInput of type instream * int -> int option.  Given a stream s and a bound n, canInput determines whether or not a call to input would immediately yield up to n characters.  If the input operation would block, canInput yields NONE; otherwise it yields SOME k, with 0<=k<=n being the number of characters immediately available on the input stream.  If canInput yields SOME 0, the stream is either closed or exhausted.  The function endOfStream of type instream -> bool tests whether the input stream is currently at the end (no further input is available from the source).  This condition is transitive since, for example, another process might append data to an open file in between calls to endOfStream.

The function output of type outstream * string -> unit writes a string to an output stream.  It may block until the sink is able to accept the entire string.  The function flushOut of type outstream -> unit forces any pending output to the sink, blocking until the sink accepts the remaining buffered output.

This collection of primitive I/O operations is sufficient for performing rudimentary textual I/O.  For further information on textual I/O, and support for binary I/O and Posix I/O primitives, see the Standard ML Basis Library.

Sample Code for this Chapter