1 SML Session September 24, 2007
Start the SML interpreter in a Unix shell with sml, and in Emacs with "M^x run-sml".
- 1+1;
val it = 2 : int
Read: "The value (val) of the last expression (it) equals (=) 2 (2) which (:) is of type integer (int)." it refers always to the last expression:
- it * it;
val it = 4 : int
The basic types are int, real, bool, string, char:
- 2;
val it = 2 : int
- 1.2;
val it = 1.2 : real
- true;
val it = true : bool
- "string";
val it = "string" : string
- #"a";
val it = #"a" : char
- [1,2,3];
val it = [1,2,3] : int list
Read: "The value of the last expression [1,2,3] is a list (list) of integers (int)."
Synonymous names for vector type: product or tuple type
- (1,1.2);
val it = (1,1.2) : int * real
Read: "The value of the last expression equals (1,1.2) which has type integer (int) in the first component and real (real) in the second component." The * says that the whole complex type is a vector type.
Already any idea why we have vector and list types? Aren't they both just collections of items?
- (1,1.2);
val it = (1,1.2) : int * real
- [1,1.2];
stdIn:9.1-9.8 Error: operator and operand don't agree [literal]
operator domain: int * int list
operand: int * real list
in expression:
1 :: 1.2 :: nil
All elements of a list must have the same type! (But there are more differences as you will see later)
What is the type of the unary minus ~ and the unary boolean function not?
- ~;
val it = fn : int -> int
- not;
val it = fn : bool -> bool
Read: "The value of not is a function (fn) that (:) maps booleans to booleans (bool -> bool)." The -> says that the whole complex type is a function type.
We are used to apply the unary minus not just to integers, but also to reals:
- ~1;
val it = ~1 : int
- ~1.3;
val it = ~1.3 : real
Thus ~ is applicable to values of different types: ~ is a overloaded function! There are several other overloaded functions: +, *, div, >, "¦
1.1.7 Infix Operator vs. Prefix Function Name
What is the type of the binary function + ?
- +;
stdIn:13.1 Error: expression or pattern begins with infix identifier "+"
Oops! + is an infix operator and that is a problem here! Fortunately each infix operator has an function name in prefix notation: If * is the infix operator then op* is its function name in prefix notation.
- 1+2;
val it = 3 : int
- op+(1,2);
val it = 3 : int
- op<(1,2);
val it = true : bool
Actually op+ is a mixed complex type:
- op+;
val it = fn : int * int -> int
Read: "op+ is a function (fn) that maps pairs of integers (int * int) to (->) integers (int)."
Note the precedence of type information given by SML! The product type constructor * binds stronger then function type constructor ->. Hence int * int -> int means without omitting braces ((int * int) -> int)!
You can combine the given types to arbitrary complex types:
- (true,[1,2]);
val it = (true,[1,2]) : bool * int list
- (1,[op+,op*]);
val it = (1,[fn,fn]) : int * (int * int -> int) list
Note another type precedence in SML: The list type constructor list binds stronger then the product type constructor *. Hence the last type expression means (int * (((int * int) -> int) list))
Value names are called variables.
1.2.1 Binding Names to Values of Basic Types
The general declaration form: val name = value : type;
The type information is optional. SML can infer it mostly.
- val pi = 3.141;
val pi = 3.141 : real
- val c = #"c";
val c = #"c" : char
- val s = "string";
val s = "string" : string
- c;
val it = #"c" : char
1.2.2 Binding Names to Values of Product Type
Giving a whole vector a name:
- val v = (1,1.2);
val v = (1,1.2) : int * real
- v;
val it = (1,1.2) : int * real
Giving each component a name:
- val (x,y) = (1,1.3);
val x = 1 : int
val y = 1.3 : real
- x;
The general declaration form: type name = complex-type;
- type vec = real * real;
type vec = real * real
We bind names to types just for convenience. They are not really "new types".
- val v = (3.1,42.1);
val v = (3.1,42.1) : real * real
- val v = (3.1,42.1):vec;
val v = (3.1,42.1) : vec
The general declaration form: fun name (formal-param:type):type = body;
The first type determines the type of the formal parameter, and the second the type of the return value. Again type information are always optional as long as SML can infer a type.
- fun square (x) = x*x;
val square = fn : int -> int
- square(3);
val it = 9 : int
1.2.5 Examples showing type inference
from the default type int -> int of *:
- fun square (x) = x*x;
val square = fn : int -> int
from explicit type information of the formal parameter (x:real):
- fun square (x:real) = x*x;
val square = fn : real -> real
from explicit type information of the return value (x):real:
- fun square (x):real = x*x;
val square = fn : real -> real
most explicit type information:
- fun square (x:real):real = x*x;
val square = fn : real -> real
- val pi = 3.141;
val it = 3.141 : real
- fun area (r) = pi*r*r;
val area = fn : real -> real
- area(1.0);
val it = 3.141 : real
- val pi = 3.1;
val pi = 3.1 : real
- area(1.0);
val it = 3.141 : real
A higher order function is a function that has functions as arguments or as return value.
A function without name and its application:
- fn x:real => x*x;
val it = fn : real -> real
- (fn x:real => x*x) 3.4;
val it = 11.56 : real
1.3.2 Function Definition with Anonymous Functions
We can define the square function conveniently as above:
- fun square (x:real) = x*x;
val square = fn : real -> real
In fact this is only an abbreviation of a regular value declaration:
- val square = fn (x:real) => x*x;
val square = fn : real -> real
The latter declaration style reveals that functions are just values!
1.3.3 Simple Higher Order Functions
A cascading function is a function which returns a function,e.g.:
- fun cascaded_plus (x) = (fn (y) => x+y);
val cascaded_plus = fn : int -> (int -> int)
- val plus1 = cascaded_plus(1);
val plus1 = fn : int -> int
- plus1(2);
val it = 3 : int
- cascaded_plus(1)(2);
val it = 3 : int
A artesian function is a function that has tuples as arguments (e.g. op+).
Note cascaded_plus(1)(2) computes the same as the Cartesian function op+(1,2).
You can always transform Cartesian to cascaded functions.