------------------------

Harvey Mudd College
Computer Science 131
Programming Languages
Spring Semester 2000

Lecture 02

------------------------

------------------------

Introduction to Standard ML

To start SML, you just type sml

For this course, though, you should generally use the command sml-cs131 defined in /cs/cs131/bin

As I described the nature of the read-eval-print loop is such that you can just type an expression and SML will respond with its value:

3;
3 + 2;

SML will always echo a TYPE along with a VALUE.

------------------------

There are two numeric base types, real and int. The usual operators, +, -, and * are defined for the integers and for the reals (but not with a mixed pair). Integer division is done with the infix operator div, while / is used for real division.

Note that - is used only for binary subtraction. The unary negation operator is written '~'. So, minus three is written ~3.

The full complement of relational operators, =, <, >, <=, >=, and <> are supported as well.

bool, the booleans, is a built in type with two values: false, and true.

May be checked for equality (and inequality), but no other comparisons or operations are allowed.

------------------------

Many built-in functions. Function application pretty much like other languages, except you don't in general use parentheses:

Math.sqrt 4.0;

You only use parentheses for grouping and precedence purposes:

Math.sqrt (4.0 + 12.0);

Notice that functions are themselves just named values:

Math.sqrt;

op +;

Real.~;

------------------------

The arrow means that sqrt is a function which takes a real and returns a real. Any violation causes an error:

Math.sqrt 3;

There is no automatic casting, period!

A few functions like plus are overloaded so they work on different types

3 + 4;
3.0 + 4.0;

But there are limits:

3 + 4.0;

Instead of general overloading, ML supports much richer notion of Polymorphism TBD later.

------------------------

Assigning a name to a value:

val x = 3+4;

3 + 4;
it + 5;

------------------------

Last base types are string and char. String constants are written with double-quotes as in C. All the relational operators described above are defined for strings.

Concatenate two strings using the ^:

val s = "Hello " ^ "World!";

Character literals are written in a slightly odd notation, as singleton strings preceeded by a '#' character:

val c = #"h";

As above, the usual relational operators are supported

SML-NJ supports the usual C-like mechanism of using the backslash to write the standard control codes, such as \n for newline and \" for the double-quote character.

The function explode takes a string and returns a list of characters (more on lists later). implode does the opposite.

------------------------

There is actually one more base type called unit, even simpler than the booleans.

It has only one value, (), which is also called unit.

Why does it exist?

------------------------

Three built-in structured types, tuples, records, and lists.

Tuples are unlabeled ordered pairs, triples, etc.

A pair of integers

(2,3)

A triple of reals

(2.3,3.4,5.6)

A quadruple of strings

("this","is","a","test")

Tuples are heterogeneous:

val bigtup = (1,true,(),"test",(2,"hello","world"),3.14159)

Can be tested for equality and inequality. They are equal if each field is equal.

You can select out the fields of a tuple using numeric selectors:

#2 bigtup;

#5 bigtup;

#2 (#5 bigtup);

These selectors are rarely used because of the availability of pattern matching.

------------------------

Records are similar to tuples but use field names rather than position to distinguish the different fields.

val emprec1 = {name="Josh",ext=8650};

Fields are selected similarly to tuples:

#ext emprec1

Records can also be compared for equality and inequality. This is done fieldwise, by the name of the field, not position:

val emprec2 = {name="Ran",ext=8976};

val emprec3 = {ext=8650,name="Josh"};

emprec1 = emprec2;

emprec1 = emprec3;

------------------------

Lists are homogeneous variable length structures. A list has a head and a tail. The head is a single item of some type. The tail is a list of that type. There is a special element named nil that is used to terminate a list. Nil is a list of arbitrary type.

The basic notation for lists uses the infix constructor :: which is pronounced `cons' for `construct'.

You would write a list of integers like:

val ilist1 = (1::2::3::nil);

No internal parentheses are needed here because cons associates to the right. So the last expression is equivalent to

(1::(2::(3::nil)));

Notice that cons takes an element on the left and a list on the right. So we can build up a list out of existing ones like:

val ilist2 = (4::ilist1);

Remember, though, that lists must be homogeneous, so:

val badlist = (1::2::3.0::4::nil);

will generate an error.

------------------------

There is a more comact notation for lists that can be used when you can enumerate all the elements of the list. Just use a pair of square braces with the elements separated by commas, with nil[].

Recall, list items can be of any first class type in the system.

val wierd1 = [(1,"hello"),(2,"goodbye")];

val wierd2 = [[1,2],[3,4,5],[6]];

val wierd3 = [op *,op div]

val wierd3a = [op *,op /]

You will need to get pretty good at reading ML types and understanding them. For instance, notice the difference between the types of:

wierd1;

and

val wierd5 = ([1,2],["hello","goodbye"]);

------------------------

As with tuples and records, lists come with a set of little-used selectors, hd which gives you the head of a list, and tl which gives you the tail of a list:

wierd2;

hd wierd2;

tl wierd2;

hd (tl wierd2);

hd (tl (hd (tl wierd2)));

(hd wierd3) (2,3);

------------------------

Code written in a file, as opposed to entered directly at the input prompt, is generally commented. The comment style in SML is the same as that for pascal: Comments have both opening and closing delimeters, which are the character pairs (* and *), respctively. So, for example:

(* This is a brief comment. *)
Since there are delimeters at both ends, comments may, obviously, stretch across multiple lines.

One of the advantages of the extremely high level of structure and abstraction provided by SML is that code is typically more self-commenting than in languages like C, so you will find the natural level of explicit commenting lighter.

As usual, take a cue from the graders and the sample solutions as to an adequate level of commenting for your code.

------------------------
This page copyright ©2000 by Joshua S. Hodas. It was built on a Macintosh. Last rebuilt on Saturday, January 22, 2000
http://www.cs.hmc.edu/~hodas/courses/cs131/lectures/lecture02s.html