(* Code for Lecture 2: Binding, Scope, Functions *) (* Bindings *) (* pi up to 2 digits *) val pi : real = 3.14; (* local bindings *) let val m:int = 3 val n:int = m*m (* n = 9 *) val k:int = m*m (* k = 9 *) in k*n (* result will be 81 *) end; (* Bindings persist -- however later binders may overshadow earlier binders. *) val k:int = 4; let val k : int = 3 in k * k (* the result will be 9! *) end; k; (* at this point k = 4 again *) (* Functions *) val area : real -> real = fn (r:real) => pi * r * r; val a2 = area (2.0); (* result a2 = 12.56 *) (* We can shadow the definition of pi. *) val pi : real = 6.0; (* now pi = 6.0 *) (* The area function will remain unchanged. ! *) val a3 = area (2.0); (* result a3 = 12.56 *) (* We can shadow area with a more accurate definition. *) val pi : real = Math.pi; fun area (r:real) = pi * r * r; val a4 = area (2.0); (* result a4 = 12.5663706144 *) (* it will use the new pi and the new area def. *) (* Recursive Functions *) (* val fact:int->int fact(n) = n! Invariant: n >= 0 Effects: none *) val rec fact:int->int = fn(n:int) => if n = 0 then 1 else n*fact(n-1); (* Here is a slightly less cumbersome way of writing this: *) fun fact(n:int):int = if n = 0 then 1 else n*fact(n-1); (* Checking the invariant (here: n >= 0) each time around the loop is often inefficient. *) exception Domain; fun fact(n:int):int = if n < 0 then raise Domain else if n = 0 then 1 else n*fact(n-1); (* Better to check the invariant for the externally visible function only, and not during recursion. *) fun fact(n:int):int = let fun f(n:int):int = if n = 0 then 1 else n*f(n-1) in if n < 0 then raise Domain else f(n) end; (* power(n,k) = n^k for k >= 0 where 0^0 = 1 *) (* power : (int * int) -> int *) fun power (n:int, k:int) = if k = 0 then 1 else n * power (n, k-1); (************************************************************************)