(* CTM Chapter #01 Examples in Alice ML *)
(* 1.1 A calculator *)
inspect (9999*9999);
(* 1.2 Variables *)
val v = 99 * 99;
inspect (v*v);
val v = IntInf.fromInt(9999 * 9999);
(* # constant coercion is on the TDL # *)
(* val v = 9999 * 9999 : IntInf.int; *)
inspect (v*v);
(* 1.3 Functions *)
fun fact 0 = 1
| fact n = n * fact (n-1);
inspect (fact 10);
(* fact(100); causes overflow exception *)
(* Using IntInf *)
fun fact' 0 = IntInf.fromInt 1
| fact' n = IntInf.fromInt (n) * fact' (n - 1);
inspect (fact' 100);
fun comb n k =
(fact n) div ((fact k) * (fact (n-k)));
inspect (comb 10 3);
(* 1.4 Lists *)
inspect [5, 6, 7, 8];
val h = 5;
val t = [6, 7, 8];
inspect (h::t);
val ns = [5, 6, 7, 8];
inspect (List.nth(ns, 0));
inspect (hd ns);
inspect (tl ns);
case ns of
h::t => (inspect h; inspect t)
| _ => ();
(* 1.5 Functions over lists *)
fun shiftLeft [] = [0]
| shiftLeft (n::ns) = n::shiftLeft(ns);
fun shiftRight ns = 0::ns;
fun addList [] _ = []
| addList _ [] = []
| addList (n1::ns1) (n2::ns2) = (n1 + n2)::(addList ns1 ns2);
fun pascal 1 = [1]
| pascal n = addList (shiftLeft (pascal (n-1))) (shiftRight (pascal (n-1)));
inspect (pascal 20);
(* 1.6 Complexity *)
fun fastPascal 1 = [1]
| fastPascal n =
let
val ns = fastPascal(n-1)
in
addList (shiftLeft ns) (shiftRight ns)
end;
inspect (fastPascal 30);
(* 1.8 Lazy evaluation *)
fun lazy ints n =
n::(ints (n+1));
val a = ints 0;
inspect (hd a);
inspect [hd a, hd (tl a), hd (tl (tl a))];
inspect [List.nth(a, 0), List.nth(a, 1), List.nth(a, 2)];
fun lazy pascalList row =
row::pascalList (addList (shiftLeft row) (shiftRight row));
val a = pascalList [1];
inspect (hd a);
inspect (hd (tl a));
inspect (hd (tl (tl (tl (tl a)))));
inspect (List.nth(a, 4));
fun pascalList2 1 row = [row]
| pascalList2 n row = row::(pascalList2 (n-1) (addList (shiftLeft row) (shiftRight row)));
val a = pascalList2 10 [1];
inspect (List.nth(a, 4));
(* 1.9 Higher-order programming *)
fun opList opn (n1::ns1) (n2::ns2) = (opn(n1, n2))::(opList opn ns1 ns2)
| opList opn a b = [];
fun genericPascal opn 1 = [1]
| genericPascal opn n =
let
val ns = genericPascal opn (n-1)
in
opList opn (shiftLeft ns) (shiftRight ns)
end;
fun addInt (a, b) = a + b;
inspect (genericPascal (fn (a, b) => (a+b)) 20);
inspect (genericPascal addInt 20);
inspect (genericPascal op+ 20);
fun fastPascal n = genericPascal addInt n;
inspect (fastPascal 20);
fun xor (x, y) =
if (x = y) then 0 else 1;
inspect (genericPascal xor 20);
(* 1.10 Concurrency *)
val p = spawn
let
val ns = pascal 20
in
inspect ns;
ns
end;
(* 1.11 Dataflow *)
val x = spawn
(
Thread.sleep(Time.fromMilliseconds(Int.toLarge(2000)));
99
);
inspect "start";
inspect (x*x);
val xf = fn n => spawn
(
inspect "start";
inspect (n*n);
n
);
Thread.sleep(Time.fromMilliseconds(Int.toLarge(2000)));
val x = xf 99;
(* 1.12 Explicit state *)
val c = ref 0;
c := !c + 1;
inspect (!c);
val c = ref 0;
fun fastPascal n =
(
c := !c + 1;
genericPascal op+ n
);
(* 1.13 Objects *)
local
val c = ref 0;
in
fun bump() =
(
c := !c + 1;
!c
);
fun read() = !c;
end;
inspect (bump());
inspect (bump());
fun fastPascal n =
(
inspect (bump());
genericPascal addInt n
);
(* 1.14 Classes *)
functor NewCounter() =
struct
local
val c = ref 0
in
fun bump() =
(
c := !c + 1;
!c
);
fun read() = !c;
end;
end;
structure Ctrl1 = NewCounter();
structure Ctrl2 = NewCounter();
inspect (Ctrl1.bump());
(* 1.15 Nondeterminism and time *)
val c = ref 0;
spawn c := 1;
spawn c := 2;
val c = ref 0;
spawn
let
val i = !c
in
c := i + 1
end;
spawn
let
val j = !c
in
c := j + 1
end;
(* 1.16 Atomicity *)
(* solution using state variables *)
val c = ref 0;
val lock = Lock.lock();
spawn Lock.sync lock
(fn () =>
let
val i = !c
in
c := i + 1
end)();
spawn Lock.sync lock
(fn () =>
let
val j = !c
in
c := j + 1
end)();
(* end solution using state variables *)
(* solution using promises and atomic exchange *)
val c = ref 0;
spawn
let
val p = Promise.promise()
val i = Ref.exchange(c, Promise.future(p))
in
Promise.fulfill(p, i+1)
end;
spawn
let
val p = Promise.promise()
val j = Ref.exchange(c, Promise.future(p))
in
Promise.fulfill(p, j+1)
end;
(* end solution using promises and atomic exchange *)
(* solution using modify for references *)
val c = ref 0;
spawn Ref.modify (fn i => i + 1) c;
spawn Ref.modify (fn j => j + 1) c;
(* end solution using modify for references *)
|