Some Standard ML information :
[ Running/Obtaining SML | On-line
Documentation | Books ]
[ Sample SML code | Typing in and
running SML code | Debugging]
-
Running/Obtaining SML
-
On the CS Dept machines : Standard ML of New Jersey (SML/NJ)
Version 0.93 is installed in /s/sml. Currently, it's been compiled
to run for Sun SPARCs running Solaris and HP "snakes" running HP-UX, so you
can run SML on the Sols/Vegas. The name of the SML/NJ interpreter is
sml and is located in /s/sml/bin. For reasons mentioned
below, it may be preferable to use a version of the SML interpreter that
comes pre-loaded with the SML Library. I've prepared such a version :
/p/course/cs538-larus/public/html/sml/sml-with-lib
(this runs on the SPARC/Solaris machines (Sols/Vegas) only).
-
On your machine at home :
-
Macs or 386 running Mach/BSD : You can obtain binaries of SML/NJ
0.93 from
Bell
Lab's FTP site. You will have to download the libraries/documentation
separately (from the same site).
-
PCs running DOS, Windows 3.x, OS/2, Linux (also Macs) : You can use
Moscow ML, a
light-weight implementation of SML provided with full sources and documentation.
It supports the Standard ML Core language, a simple version of modules and
much of the SML Basis library.
-
On-line Tutorials/Guides/Documentation
-
Books
-
The two books mentioned by Prof Larus in class should provide enough information
on SML for the assignment.
-
-
L C Paulson : ML for
the Working Programmer, 2nd ed ('96), Cambridge University Press
($32.95 at UBS). [Caveat : The newer edition of this book deals with a more
recent version of ML than the one installed locally, so some of the library
functions used in the book may not exist.]
-
Jeffrey D Ullman : Elements of ML Programming, ('94), Prentice-Hall.
You can also check out the
Literature
section of the SML/NJ
web site at Bell Labs for names of more books on ML.
For functional programming in general, you can try to get hold of Chris Reade's
Elements of Functional Programming (this uses ML), Field & Harrison's
Functional Programming or Richard Bird and Philip Wadler's
Introduction to Functional Programming.
-
Sample SML code
-
You can check out some of the sample code that comes
with the SML/NJ 0.93 distribution. You can also check out the
source code of the SML Standard Library. The on-line
ML tutorials on the web-page provided by Prof Larus
also contain sample ML code.
-
-
Typing in and running SML code
-
-
Starting up and exiting SML/NJ
SML/NJ is an SML interpreter. You can type in code and interactively see
its output as it is run. To fire up the interpreter, type sml (you
must be on a SPARC/Solaris or HP-snake/HP-UX machine first). You should see
something like this come up :
sol36(3):~% sml
Standard ML of New Jersey, Version 0.93, February 15, 1993
val it = () : unit
-
The '-' is the SML prompt. Now you can type in ML code and the
interpreter immediately evaluates it and produces an output. (The italics
indicate stuff I typed in, the rest is produced by SML, comments are anything
within (* and *)). You need a terminating semicolon
at the end of each definition you type . Control-C interrupts the interpreter
and returns you to the top-level prompt.
- val my_age = 23; (* define an integer variable*)
val my_age = 23 : int
- fun grow_old age:int = age + 25; (* define a function that increases
my age*)
val grow_old = fn : int -> int
- grow_old my_age;
val it = 48 : int
- grow_old 15;
val it = 40 : int
- grow_old 10.0;
std_in:6.1-6.13 Error: operator and operand don't agree (tycon mismatch)
operator domain: int
operand: real
in expression:
grow_old 10.0
-
To exit, either type Control-D at the prompt or call System.Unsafe.
CInterface.exit() :) ...
-
Reading in an SML program from a file
The interpretive mode is great for testing out functions one by one but it's
useless for typing in lots of functions or making changes to them. SML provides
you with a function for reading in an SML program from a file. The function
is use ( type = string -> unit). Suppose that you had
typed in the following SML code into a file called hello.sml :
fun hello () = output( std_out, "Hello, world\n" );
Now, we fire up SML and read in this file :
sol36(8):~% sml
Standard ML of New Jersey, Version 0.93, February 15, 1993
val it = () : unit
- use "hello.sml";
[opening hello.sml]
val hello = fn : unit -> unit
val it = () : unit
- hello;
val it = fn : unit -> unit
- hello ();
Hello, world
val it = () : unit
-
-
Using the SML library
The SML Standard Library is divided into two parts -- the Base
Environment and the rest of the library. The Base environment
(also called the initial/ pervasive/ standard environment) is always available
and is loaded automatically when you fire up the SML interpreter. To use
the rest of the library, you would have to explicitly load source files from
the library directory. This can be a bit of a pain, so I prepared a version
of the SML interpreter where the entire library (not just the Base) is pre-loaded
and always available. This version (for SPARC/Solaris machines only) is available
as ~cs538-1/public/html/sml/sml-with-lib.
The SML Standard Library is organized as a collection of structures
(you will have to get familiar with the modules facility of SML).
A structure is basically a self-contained collection of type/ exception/
function declarations grouped together because they provide some common
functionality. Typically, they implement abstract data types or provide some
system utility functions. For example, the IO structure is part
of the Base environment and it declares some standard streams
(std_in, std_out) and some I/O functions including
input and output. These declarations are local to the
structure. So to reference them you would have to prefix the name of the
structure for e.g. you would have to say
IO.output( IO.std_out, "Hello" );
This can get cumbersome so SML provides the open declaration which
"opens up" the structure and makes all the local declarations visible at
the scope level of the open. So I could reword the above as :
open IO;
output( std_out, "Hello" );
When you open a structure, SML spits out a long list of type declarations
-- this is the signature of the structure : the type declarations
of all the members of the structure. The signature is a means of providing
the interface of a structure to the outside world. When you learn about modules,
you will see that signatures can combine with functors to provide
powerful structuring mechanisms.
As it happens, SML automatically opens some standard structures from the
Base environment (including IO) to save you from having to keep
opening commonly used structures. I suggest that you now go through the
documentation of the SML Standard Library provided in the documentation section
above -- they list the structures and their interfaces, so you can try opening
them up and playing around with the functions defined in them. In particular,
check out the following structures :
-
(Base) List, String, Int, Real, IO
-
(Lib) CType, StringCvt, Format, ListUtil, MakeString,
StringUtil
-
Preparing an executable/saving the current environment
During an interactive session with SML, you may have defined several functions
or structures which are present in the current environment and which you
might want to save for future sessions. SML provides you with a function
to save the current environment : exportML (type = string ->
bool). So typing in
exportML "saved_env";
will create a HUGE file called saved_env which is basically a dump
of the entire memory contents (including the code for the interpreter and
the environment). Later you can RUN this file (you can't load it into SML)
from the shell command line to get back to a SML prompt with your previous
environment restored. Beware : the saved file can be quite huge (will be
at least 4MB on the Sols/Vegas).(BTW this is the method I used to prepare
sml-with-lib).
You can also prepare an executable from your SML code much as you would use
a compiler for other languages. You first have to define a function
that takes as parameter a tuple of two lists of strings ( the command-line
arguments and environment strings, much as you need to define a main
function in C/C++ that takes an argument count and list of arguments as
parameters). You can then use the exportFn function to create an
executable that starts execution at this function. For example :-
sol36(18):sml% sml
Standard ML of New Jersey, Version 0.93, February 15, 1993
val it = () : unit
- fun hello (args, env) = output( std_out, "Hello, world\n" );
val hello = fn : 'a * 'b -> unit
- exportFn( "helloworld", hello );
[Major collection... 3% used (17964/564444), 10 msec]
[Decreasing heap to 91k]
[Major collection... 99% used (18124/18204), 0 msec]
sol36(19):sml% ls -l helloworld
-rwxr-xr-x 1 plakal 3516804 Mar 20 19:51 helloworld
sol36(20):sml% helloworld
Hello, world
sol36(21):sml%
Of course, more realistic programs would actually make use of the command-line
parameters.
-
Debugging/Programming Environments
-
There is no debugger installed with SML/NJ as of present (it requires building
a special version of the SML interpreter that can then interact with GNU
Emacs), but SML isa strongly typed language and its type inference system
is quite powerful and can capture a lot of errors and ambiguities. Furthermore,
there is run-time checking so there's no way you can crash the system (except
for an infinite loop of course). SML does provide you with references which
are pointers (and hence dangerous :) ) but their use is deprecated as not
being in the functional style.
Harlequin has come up with a GUI-based programming environment for ML called
MLWorks --
unfortunately, it's not free :( ... around $750 for the Windows version and
$2000 for the Unix versions (though academic discounts are available).