Standard ML is a language divided into two sections: the core system and the module system. It was originally intended to be in interactive language, so the language has been highly influenced by this. We will begin by bringing up an interactive "top-level" environment where we can begin to explore Standard ML.
$ poly Poly/ML 5.6 Release >
This top-level environment provides complete access to the language. We can type simple expressions and press [Enter] to have the expression evaluated. As you can see, the result is stored into a value "it".
> 1 + 1; val it = 2: int > 1.0 + 1.0; val it = 2.0: real
In Standard ML (unlike OCaml), integers and floats share the same operators.
Note: The semicolon in the Standard ML top-level is used to delimit top-level "declarations". Outside of the top-level, it is primarily used to disambiguate the end of an expression. We'll see more of this in the future.
String concatenation, however, uses another operator.
> "foo" ^ "bar"; val it = "foobar": string
We can store values easily as well.
> val i = 1 + 1; val i = 2: int > val s = "foo"; val s = "foo": string
In the event of an ambiguous right-hand expression, or just to provide extra clarity, we can annotate the type of the value we are declaring.
> val i : int = 1 + 1; val i = 2: int > val s : string = "foo"; val s = "foo": string
In fact, we can annotate the type of basically anything anywhere. This can be incredibly useful as assertions during debugging. For instance, when tracking down a type error it can be helpful to explicitly and verbosely annotate types to pinpoint the exact location of the type error.
> val i = (((2 + 2): int) - 1): int; val i = 3: int
Standard ML provides some basic vector types in addition to the previously demonstrated scalar types. We will focus primarily on lists and tuples here.
> val tuple = (1, 2); val tuple = (1, 2): int * int > val list = [1, 2]; val list = [1, 2]: int list
An asterisk between two types always indicates a tuple. And a list is a special kind of type we call "polymorphic". A generic list might have type "'a list" where each element of the list is of the type variable "'a". In the previous example, the elements of the list are of type int.
Standard ML provides special tools for deconstructing elements of tuples and lists.
> val (a, b) = (1, 2); val a = 1: int val b = 2: int > val (hd :: tl) = [1, 2]; val hd = 1: int val tl = : int list
This deconstructing is very powerful and will show up in many places. For now, we'll go one step further and introduce arbitrary nested deconstructing of tuples and lists.
> val (a, b) :: ((c, d) :: tl) = [(1, 2), (3, 4), (5, 6)]; val a = 1: int val b = 2: int val c = 3: int val d = 4: int val tl = [(5, 6)]: (int * int) list