CSCI 384 Fall 2021

A quick guide to Standard ML

Below is a subset of the language Standard ML. We’ll be learning it as an example of a “functional programming language” or FPL. Such programming languages, when used “purely”, have you program by writing a series of functions that don’t produce side effects. For example in typical use there are no loops (most code is recursive) and variables can’t be modified. Data structures are more naturally devised to be immutable

FPL programs “run” by the system evaluating the functions you write, calculating values that you want to compute. The style of programming is more mathematical than the standard “procedural” or “object state-changing” programming languages you’ve learned. They can be more easily modeled with mathematics, as a result.

In such languages, functions are first class. This typically means that functions can be passed around as if they are data values. For example:

• they can be passed as parameters to functions
• they can be returned as values to functions
• they can be expressed succinctly, without naming them (with something like the Python/C++ lambda expression.

Modern languages like C++, Python, Java, and Rust have worked to incorporate many of these features into their coding. There can be advantages to writing in this style. For example, immutable data structures are often more easily shared amongst different code components, or amongst several running threads. It’s sometimes, then, more easy to reason about, or control, data allocation and de-allocation. The software industry has noticed that using FPL-style coding can sometimes lead to less buggy code. It has also built more sophisticated libraries (e.g. GUI callbacks, general sorting and data processing algorithms) using FPL-style constructs.

Many FPLs will have sophisticated type systems that ensure that you write code that is careful about the types of the data values used by your program. They don’t allow you to mix up types and they check that your code won’t have any run-time (i.e. evaluation-time) type errors— e.g. that you don’t add an integer to a boolean value. The type system doesn’t let you loosely use types, excepting maybe with a careful “datatype” declaration that allows one type to have many variants, and also with polymorphic functions and values. Furthermore, the type checking engine is clever enough to not require you to

Standard ML was one of the first languages to have this kind of type checking according to the Hindley-Milner type system. (Robin Milner was the original ML’s lead inventor.) It was first built to write automated theorem-proving systems. Its design seems to be inspired by several sophisticated concepts from the study of mathematical logic. And it also got adopted by programming language researchers as a language for “meta-programming”, that is, writing code that processes and reasons about programmer’s code.

ML was named for “meta language.”

We study Standard ML now so as to mathematically model it soon. We will do so by replicating the SML/NJ system, inventing our own interpreter for a language MiniML.

—– running the SML/NJ REPL —–

Enter the terminal command:

rlwrap sml

This brings up the “read-eval-print loop” (or REPL) of the SML/NJ interpreter.

Hit CTRL-d to exit.

—– REPL interaction —–

<cmd> ::= use "filename.sml";
<cmd> ::= <expn>;
<interaction> ::= <cmd> <cmd> ... <cmd>

—– source code —–

<src> ::= <defn> <defn> ... <defn>

—– name-value binding —–

<expn> ::= name
<expn> ::= let <defn> ... <defn> in <expn> end
<defn> ::= val <name> = <expn>

—– functions —–

<defn> ::= fun <name> <name> ... <name> = <expn>
<expn> ::= <name> <expn> ... <expn>
<expn> ::= fn <name> => <expn>

—– arithmetic —–

<expn> ::= <expn> <binop> <expn>
<expn> ::= <unop> <expn>
<binop> ::= + | - | * | div | mod
<unop>  ::= ~
<expn> ::= ... | ~2 | ~1 | 0 | 1 | 2 | ...

—– conditional expression —–

<expn> ::= if <expn> then <expn> else <expn>

—– comparison and logic —–

<binop> ::= andalso | orelse
<binop> ::= < | <= | >= | > | = | <>
<unop>  ::= not
<expn> ::= true | false

—– lists —–

<expn> ::= <expn> :: <expn>
<expn> ::= nil
<expn> ::= [ <expn> , ... , <expn> ]
<expn> ::= null <expn> | hd <expn> | tl <expn>

—– tuples —–

<expn> ::= ( <expn> , ... , <expn> )
<expn> ::= #1 <expn> | #2 <expn> | ...

—– other basic types —–

<expn> ::= ()
<expn> ::= "hello" | ...
<expn> ::= #"a" | #"b" | #"c" | ...

—– types —–

<type> ::= int | bool | unit | string | char
<type> ::= <type> -> <type>
<type> ::= <type> * <type> * ... * <type>
<type> ::= <type> list
<type> ::= 'a | 'b | 'c | ...