(* 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 *) |