15-212: Principles of Programming

Language and Programming Environment

The programming environment we will be using for the course will be the Standard ML of New Jersey system (known as SML/NJ). This guide provides instructions for how to set up your Andrew account to use SML/NJ, and a brief introduction to using the SML/NJ system. This is not intended as a guide to programming in Standard ML; for that purpose you are referred to the course textbook and the on-line notes.

Standard ML is a safe, modular, strict, functional, polymorphic programming language with compile-time type checking and type inference, garbage collection, exception handling, immutable data types and updatable references, abstract data types, and parametric modules. It has efficient implementations and a formal definition with a proof of soundness. For explanations of these terms see "What is Standard ML?"

Click here to skip ahead to the Web Notes section, which contains links to the basis library.

Installation and Use of SML/NJ

How to run SML/NJ at CMU

Personal Copies of SML/NJ

To use SML/NJ on your own machine please visit the SML/NJ homepage.
NB: The version installed on Andrew is 110.69. The TAs will use this version to grade assignments. You may wish to install it on your own machine. It is available here.

A convenient way to run SML/NJ is via the SML mode for Gnu Emacs. See this page for additional details.

Starting SML/NJ

With your .emacs file set up for SML, you may enter SML mode either by loading any file with a .sml or .sig extension, or by typing M-x sml-mode. The SML mode provides indentation and other facility that may be helpful in editing SML source code.

Once in the SML mode, you can start SML/NJ by typing M-x sml, or by selecting SML/Process/Start default ML compiler from the menu. This will start SML/NJ running in the background. You can then bring up an SML/NJ window by typing C-c C-s, or by selecting SML/Process/switch to ML buffer from the menu. On some machines SML/NJ may be slow to load; if the window comes up empty, be patient.

If you prefer not to run SML/NJ through Emacs, you may also run it from the Unix prompt at path /afs/andrew/course/15/212sp/bin/sml.

Interacting with SML/NJ

Once SML/NJ has started, it prints the current version number and then prompts for user input. The prompt is a single dash. At the prompt you may type an SML top-level declaration or an SML expression. When you enter a declaration, SML/NJ evaluates the declaration, prints its result value and type, and prompts for more input. For example:

- val a = 2 + 3;
val a = 5 : int

This declaration sets a equal to the value of 2 + 3, that is, 5. The semicolon at the end of the input line tells the SML parser that its input is complete. By leaving off the semicolon you may enter multi-line declarations or expressions. Each line after the first is prompted by an equals. For example, we may declare a two-line increment function by:

- fun inc x =
= x + 1;
val inc = fn : int -> int

In each of the above examples, the identifier being declared (a or inc) is available in code that follows. When you enter an expression at the user prompt, SML/NJ treats that expression as a declaration for the identifier it. For example:

- inc a;
val it = 6 : int
- it * 3;
val it = 18 : int

Using files

The interactive loop, as the above is called, is a convenient way to evaluate small expressions and declarations, but it is not practical for larger pieces of code. For larger pieces of code we want to load them directly into SML/NJ from a file. This is done by running the use command. SML/NJ will then process the file as if it had been entered into the interactive loop (except that no semicolon is needed at the end of the file). For example, suppose the file myprog.sml contained the code:

val b = 3 + 4
val c = 6 * b

Then using that file will cause SML/NJ to respond:

- use "myprog.sml";
[opening myprog.sml]
val b = 7 : int
val c = 42 : int
val it = () : unit

The final binding to it happens because SML/NJ views use "myprog.sml" as an expression and, as discussed above, treats that expression as a declaration for the identifier it. The value of this expression is (), which is pronounced ``unit.''


When SML/NJ prints a data structure, it prints that data structure only to a certain depth. Beneath that depth it prints a # instead. This is generally a good thing, since data structures can be very large (and even cyclic). However, the default depth to which SML/NJ prints data structures is 5, which is usually not enough. You can adjust the depth to which it prints data structures by entering, for example,

- Control.Print.printDepth := 10;

to set the depth to 10. SML/NJ also abbreviates lists and strings over a certain length. You can set the length at which this happens by setting Control.Print.printLength and Control.Print.stringDepth, in a manner analogous to the above.

When the argument to use is not a full path name, SML/NJ looks for source files in the working directory. You can set SML/NJ's working directory by entering, for example,

- OS.FileSys.chDir "newdir";

to change the working directory to ``newdir.'' Windows users should note that the SML syntax for strings doubles backslashes. You can also find out what the working directory is with the command:

- OS.FileSys.getDir ();

Web Notes

Local Guide

Here are the Principal SML Basis Libraries:

SML Basis Library Overview
Top-level Environment
SML Basis Manual Pages

[ CS 15-212 Home page | schedule | language | assignments | handouts | hints etc ]

Michael Erdmann