To start the interpreter, at the Unix command line, type
sml. To exit the interpreter, type ^D (control +
D) (section 1.2 in Ullman). If you are using a Windows or
(lamentably) a DOS machine, type ^Z instead.
Note: There is an executable file in
must either run this file to start SML, or copy this file to a place
in your path before you can use it.
SML/NJ is a command-line interpreter. It is not an integrated
development environment. Therefore, you must create and edit source
code files using your favorite text editor. Save your source files
with the extension
.sml. The interpreter doesn't
care what the extension is, but SML/NJ files customarily end with this
Ideally, you will have more than one window open on your desktop, be
it in X-Windows, Microsoft Windows 95/98/NT, or Be. In another
window, start the SML interpreter, but make sure you are first in the
same directory where the source file is saved. This makes your life
much easier. When the SML prompt appears, type
"filename.sml";. The file will then be loaded, and lots of
information will be displayed. If the last line is
val it =
() : unit, then it loaded successfully. If one or more
error messages were displayed, then the file did not load and you need
to fix the errors in your source file.
Read chapter 1 and 2 of the Ullman book, try as many of the examples as possible. It is helpful to sit at a computer running ML as you read the book, and try things out as you read about them.
SML/NJ is available on the Unix computers, but feel free to get it for your own computer. I'm not sure if the SML/NJ dialect will be necessary (CAML and OCAML are notable alternatives), but you should stick with it just in case.
The ML interpreter is a read-eval-print loop. The user enters expressions at the SML command prompt, and the interpreter evaluates the expression and displays the result. (Chapter 1)
An expression is terminated by a semicolon.
A variable is declared and defined using the ``val'' keyword.
val x = 10;
This creates a new entry in the environment. Once bound, a variable's value can't be changed. A new binding using the same symbolic name can be created, and it overrides the existing one (but it does not replace it).
Be sure to read and understand example 2.24 on page 32 (which deals with rebinding values in an environment).
A list in ML is a linked list, and it is similar to a list in Lisp or Scheme. The difference is that a list in ML may only contain objects of the same type. A tuple is similar to a record structure in C or Pascal, and the elements can be of any type.
Parentheses are used to create tuples, and the ``
#'' accessor can
be used to access fields in a tuple:
> val t = (4, 5.0, "six"); val t = (4, 5.0, "six") : int * real * string > #1(t) val it = 4 : int
(Although by using functions there is a more effective method of accessing tuple fields.)
A tuple can be used to pass arguments to a function, to bind values to a variable, and to return values from a function. A tuple can contain any type of object in any position, including a list or another tuple.
A list is created by using square brackets, and commas separate
elements in a list. Elements in a list must all be of the same type.
hd'' and ``
tl'' operators are used to access elements of a list.
> val m = [1, 2, 3]; val m = [1, 2, 3] : int list > hd(m); 1 : int > tl(m); [2, 3] : int list
(Although, as with tuples, functions provide a better way to access list elements.)
::'' is the list constructor, ``
@'' is the list concatenator.
> 1::2::3::nil; [1, 2, 3] : int list > 1::[2, 3]; [1, 2, 3] : int list > [1, 2] @ [3, 4]; [1, 2, 3, 4] : int list
ML's types are all built upon the basic types and tuples and lists. Be sure to read and understand section 2.4.6 and example 2.38 in Ullman.