(* Programming language concepts, seminar 1, 2002-02-04 *)
(* The meta language Standard ML, a crash course *)
(* SML arithmetic expressions, the int type *)
3+4;
(* SML variables and binding *)
val res = 3+4;
res;
(* SML arithmetic expressions, the real type *)
Math.sqrt 2.0;
(* SML logical expressions, the bool type *)
3 < 4;
val res = 3 < 4;
(* SML conditional expressions *)
if 3 < 4 then 117 else 118;
(* SML string expressions *)
val title = "Professor";
val name = "Lauesen";
val junkmail = "Dear " ^ title ^ " " ^ name ^ ", You have won $$$!";
val n = size junkmail;
val junkmail2 =
String.concat["Dear ", title, " ", name, ", You have won $$$!"];
(* SML: limiting the scope of a binding *)
val x = 5;
let
val x = 3 < 4
in
if x then 117 else 118
end;
x; (* outer x still has the value 5 *)
local val x = 3 < 4 (* a new x is declared *)
in
val z = if x then 117 else 118
end;
x; (* outer x still has the value 5 *)
(* SML function declarations *)
fun circleArea r = Math.pi * r * r;
val a = circleArea 10.0;
fun double x = 2.0 * x;
double 3.5;
fun junkmail title name =
"Dear " ^ title ^ " " ^ name ^ ", You have won $$$!";
fun junkmail title name =
String.concat["Dear ", title, " ", name, ", You have won $$$!"];
(* SML recursive function declarations *)
fun fac n = if n=0 then 1 else n * fac(n-1);
fac 7;
(* SML pattern matching *)
fun fac 0 = 1
| fac n = n * fac(n-1);
fac 7;
(* SML case expressions *)
fun fac n =
case n of
0 => 1
| _ => n * fac(n-1);
fac 7;
(* SML pairs and tuples, product types *)
val w = (2, true, 3.4, "blah");
fun add (x, y) = x + y;
add (2, 3);
val noon = (12, 0);
val talk = (15, 15);
fun earlier ((h1, m1), (h2, m2)) =
h1
23 then raise IllegalHour
else h * 60;
(* SML datatypes *)
datatype person =
Student of string (* name *)
| Teacher of string * int (* name and phone no *)
val people = [Student "Niels Jørgen", Teacher("Peter", 831)];
fun getphone (Teacher(name, phone)) = phone
| getphone (Student name) = raise Fail "no phone";
(* The option datatype *)
datatype intopt =
SOME of int
| NONE
fun getphone (Teacher(name, phone)) = SOME phone
| getphone (Student name) = NONE;
(* Representing binary trees using recursive datatypes *)
datatype inttree =
Lf
| Br of int * inttree * inttree;
val t1 = Br(34, Br(23, Lf, Lf), Br(54, Lf, Br(78, Lf, Lf)));
fun sumtree Lf = 0
| sumtree (Br(v, t1, t2)) = v + sumtree t1 + sumtree t2;
val t1sum = sumtree t1;
(* Representing object language expressions using recursive datatypes *)
datatype expr =
CstI of int
| Prim of string * expr list
val e1 = CstI 17;
val e2 = Prim("+", [CstI 3, CstI 4]);
val e3 = Prim("+", [Prim("*", [CstI 7, CstI 9]), CstI 10]);
(* Evaluating expressions using recursive functions *)
fun eval (e : expr) : int =
case e of
CstI i => i
| Prim("+", [e1, e2]) => eval e1 + eval e2
| Prim("*", [e1, e2]) => eval e1 * eval e2
| Prim("-", [e1, e2]) => eval e1 - eval e2
| Prim _ => raise Fail "unknown primitive";
val e1v = eval e1;
val e2v = eval e2;
val e3v = eval e3;
(* Changing the meaning of subtraction *)
fun eval (e : expr) : int =
case e of
CstI i => i
| Prim("+", [e1, e2]) => eval e1 + eval e2
| Prim("*", [e1, e2]) => eval e1 * eval e2
| Prim("-", [e1, e2]) =>
let val res = eval e1 - eval e2
in if res < 0 then 0 else res end
| Prim _ => raise Fail "unknown primitive";
val e4v = eval (Prim("-", [CstI 10, CstI 27]));
(* Association lists map object language variables to their values *)
val env = [("a", 3), ("c", 78), ("baf", 666), ("b", 111)];
val emptyenv = []; (* the empty environment *)
fun lookup [] x = raise Fail (x ^ " not found")
| lookup ((y, v)::r) x = if x=y then v else lookup r x;
lookup env "c";
(* Object language expressions with variables *)
datatype expr =
CstI of int
| Var of string
| Prim of string * expr list
val e1 = CstI 17;
val e2 = Prim("+", [CstI 3, Var "a"]);
val e3 = Prim("+", [Prim("*", [Var "b", CstI 9]), Var "a"]);
(* Evaluation within an environment *)
fun eval e (env : (string * int) list) : int =
case e of
CstI i => i
| Var x => lookup env x
| Prim("+", [e1, e2]) => eval e1 env + eval e2 env
| Prim("*", [e1, e2]) => eval e1 env * eval e2 env
| Prim("-", [e1, e2]) => eval e1 env - eval e2 env
| Prim _ => raise Fail "unknown primitive"
val e1v = eval e1 env;
val e2v1 = eval e2 env;
val e2v2 = eval e2 [("a", 314)];
val e3v = eval e3 env;
(* Object language expressions with variable bindings and nested scope *)
datatype expr =
CstI of int
| Var of string
| Let of string * expr * expr
| Prim of string * expr list
val e1 = Let("z", CstI 17, Prim("+", [Var "z", Var "z"]));
val e2 = Let("z", CstI 17,
Prim("+", [Let("z", CstI 22, Prim("*", [CstI 100, Var "z"])),
Var "z"]));
fun eval e (env : (string * int) list) : int =
case e of
CstI i => i
| Var x => lookup env x
| Let(x, erhs, ebody) =>
let val xval = eval erhs env
val env1 = (x, xval) :: env
in eval ebody env1 end
| Prim("+", [e1, e2]) => eval e1 env + eval e2 env
| Prim("*", [e1, e2]) => eval e1 env * eval e2 env
| Prim("-", [e1, e2]) => eval e1 env - eval e2 env
| Prim _ => raise Fail "unknown primitive"
val e1v = eval e1 emptyenv;
val e2v = eval e2 emptyenv;