What is CS312 About?

Course overview information is available here.

Background on ML

A large number of programming languages has been developed over time. Here are a few examples:

By now, you are probably familiar with at least a few of the languages above. Languages evolve over time, in parallel with the development of relevant theories, but also in direct relation to the increased computational and communication performance brought forth by technological advance. New needs lead to old languages being extended (say, by adding  object-oriented features to a language that did not have them before), or new languages being created. In fact, if you will stick long enough with the field of Computer Science, you will likely develop your own small languages. The existence of so many programming languages clearly shows that there is no one "best" language.

While there are a few general-purpose languages (like Java, or C/C++), most of them are specialized. If you have a mathematical problem to solve, it is likely that you will prefer Matlab or Mathematica to plain C, for example. SQL is much more suited to solve database problems than Basic. The latter statement is likely to be perceived as trivially obvious by those who know these two languages - and this illustrates how vastly different the features and the domain of use of various languages can be. Choosing the right programming language (or languages) for the right problem or project is a critical step on the path to success. 

While there are so many of them, programming languages can be studied and broadly grouped together based on the programming paradigms and models that they implement.

There are three main programming paradigms in use today:

SML is a modern general purpose functional programming language. SML is a statically-typed, type-safe language.

Every entity in SML has a type. This is not unusual in modern programming languages; for example, Java requires the programmer to declare a type for every variable, function argument, return value, etc.

SML does not require explicit type specifications for all identifiers (e.g. function arguments), but it uses the information implicitly present in the program to unambiguously infer the type of all identifiers before the program is run. At that time the only information available is the text of the program. We say that SML is statically-typed.

Take a look at this - admittedly contrived - example:

fun bad(isString, x):int = if isString
                           then size(x)
                           else x

Function bad declares that it returns an integer. Because of its use in the if statement, SML is able to infer that isString must be of type bool. Now if isString is true, then we apply the size operator to x. This operator can be applied only to strings, and returns the length of the string, an integer. If isString is false, then the function returns its second argument, x. Because the function must return an integer, if isString is false, then x must be an integer. Thus, depending on the value of isString argument x could be both a string or an int. No other types are acceptable for x.

At run time, when this function is called, the system will know both the value of x and that of isString. Type checking could be done at that time, dynamically, to catch any illegal values, operations, or results. Obviously, this provides a lot of flexibility. On the other hand, the checks must be performed at every call, since there is no guarantee that the arguments will be of the right type for any of these calls. Some languages do just this. SML, being statically-typed, will reject this function because of the ambiguities, and it will not even attempt to run the program.

Unfortunately, it is not possible to determine in general whether a program contains type errors using only static type-checking. All statically-typed languages deal with this conservatively, by rejecting some programs that are, in fact, correct.

SML is type-safe: once it accepts a program as being correct, it guarantees that no type-wise illegal operations will be performed during the execution of that program (e.g. it guarantees that not two strings will be multiplied). Correctness here refers only to types, it is possible to perform the wrong operations due to logic errors (e.g. you can still add 1 to an integer, rather than subtract 1 from it - but SML guarantees that a program that starts to run will never attempt to add 1 to a string).

SML (and SML/NJ in particular) supports a number of advanced features:

What is ML used for today?

In truth, not a lot when compared to something like C, C++, or Java.  ML's real strength lies in language manipulation (i.e., compilers, analyzers, verifiers, provers, etc.)  This is not surprising since ML evolved from the domain of theorem proving.