Sample Solutions to HW 1 1. Field & Harrison problems 6.1 The free variables are marked by F, the bound by B. (a) (\x.x y) (\y.y) B F B (b) \x\y.z(\z.z(\x.y)) F B B (c) (\x\y.x z (y z)) (\x.y (\y.y)) B F B F F B 6.2 (ii,a,b) (\x\y.x (\z.y z)) (((\x\y.y) 8) (\x.(\y.y) x)) ---eta-- ---eta------- ---beta(LI)- --beta-- ----------------beta(LO)---------------------- LO = leftmost outermost; LI = leftmost innermost Actually, the eta redex is left of the first innermost beta redex, but it doesn't normally count. (c) (\x\y.x (\z.y z)) (((\x\y.y) 8) (\x.(\y.y) x)) -> \y.(((\x\y.y) 8) (\x.(\y.y) x)) (\z.y z) (WEAK HEAD NORMAL FORM) -> \y.((\y.y) (\x.(\y.y) x)) (\z.y z) -> \y.(\x.(\y.y) x)(\z.y z) -> \y.(\y.y)(\z.y z) -> \y.\z.y z (NORMAL FORM) (Note that if we do eta reductions too, we get the simpler normal form \x.x. This is not a contradiction, merely a distinction between "beta-normal form" and "beta-eta-normal form".) 6.5 (a,i) \x.x (a,ii) \x.0 (c) The normal form of the expression in 6.2.iii. is just 6. This makes sense because the expression is just Y ((\a\b.a)(+ 1 5), i.e., Y(\b.6), where Y is the fixed point combinator. 6.7 (a,i) AND TRUE TRUE = (\x\y.x y FALSE) (\x\y.x) (\x\y.x) ->* (\x\y.x) (\x\y.x) FALSE ->* (\x\y.x) = TRUE (a,ii) NOT = \b.b FALSE TRUE or NOT = \b\x\y.b y x XOR = \a\b.a (NOT b) b 6.8 (a) (\.\.0 (\.0 2) 1) (b) (\.(\.0 0)(\.0 (\.2))) (c) (\.+ 0 ((\.0) (- 0 (\.3)(\.0 0)))) 2. File lambda.sml gave you ADD = \a.\b.\f.\x.a f (b f x). An alternative is to use SUCC = \n.\f.\x.f (n f x) and define ADD' = \a.\b.a SUCC b = \a.\b.a (\n.\f.\x.f (n f x)) b Note that ADD and ADD' are NOT equivalent under beta/eta conversion, though they behave the same way on Church numerals. 3.a. (* A straightforward solution: *) let rec cbv (e:exp) : exp = let rec cbv1 (e:exp) : exp option = match e with App(a,b) -> begin match cbv1 a with Some a' -> Some(App(a',b)) | None -> match cbv1 b with Some b' -> Some(App(a,b')) | None -> match a with Abs(v,e) -> Some(subst b v e) | _ -> None end | Abs(v,b) -> begin match cbv1 b with Some b' -> Some(Abs(v,b')) | None -> None end | Var v -> None in match cbv1 e with Some e' -> cbv e' | None -> e (* A trickier but more efficient solution: *) let rec cbv (e:exp) : exp = match e with App(a,b) -> let a' = cbv a in let b' = cbv b in begin match a' with Abs(v,e) -> cbv (subst b' v e) | _ -> App(a',b') end | Abs(v,e) -> Abs(v,cbv e) | Var v -> Var v 3.b. (* Straightforward: *) let rec cbn e = let rec cbn1 = function App(a,b) -> begin match a with Abs(v,e) -> Some(subst b v e) | _ -> begin match cbn1 a with Some a' -> Some(App(a',b)) | None -> begin match cbn1 b with Some b' -> Some(App(a,b')) | None -> None end end end | Abs(v,e) -> begin match cbn1 e with Some e' -> Some(Abs(v,e')) | None -> None end | Var v -> None in match cbn1 e with Some e' -> cbn e' | None -> e (* Trickier: *) let rec cbn (e:exp) : exp = match e with App(Abs(v,e),b) -> cbn (subst b v e) | App(a,b) -> let a' = cbn a in begin match a' with Abs(v,e) -> cbn (subst b v e) | _ -> App(a',cbn b) end | Abs(v,e) -> Abs(v,cbn e) | Var v -> Var v 5. Here are the diffs: Add these constructors to datatype exp: 8a9,10 > | Const of int > | Plus Add this case to bottom of isfree: 15a18 > | _ -> false Add this case to subst: 35a40 38a42 > | _ -> e' Add this case to reduce: 44a49 > | App(App(Plus,Const i),Const j) -> Const(i+j) and generalize this case in reduce: 47c52 < | Var _ -> e --- > | _ -> e Add these cases to showexp: > | Const i -> print_int i > | Plus -> print_string "+" 6. type dexp = Dabs of dexp | Dapp of dexp * dexp | Dvar of int exception NotClosed let convert (e:exp) : dexp = let rec c (e,env) = match e with Abs(s,e) -> Dabs(c(e,s::env)) | App(e1,e2) -> Dapp(c(e1,env),c(e2,env)) | Var s -> let rec calc_index (env,ind) = match env with [] -> raise NotClosed | (h::t) -> if h = s then ind else calc_index(t,ind+1) in Dvar(calc_index(env,0)) in c (e,[]) (* handy for debugging: *) (* dshow d prints an abbreviated concrete syntax representation of d to stdout *) let dshow (d:dexp) : unit = let rec print_dexp d = match d with Dabs _ -> (print_string "("; print_dabs d; print_string ")" ) | Dapp _ -> (print_string "("; print_dapp d; print_string ")") | Dvar i -> print_int i and print_dabs d = match d with Dabs d -> (print_string "\\."; print_dabs d) | _ -> print_dapp d and print_dapp d = match d with Dapp(a,b) -> (print_dapp a; print_string " "; print_dexp b) | _ -> print_dexp d in print_dexp d; print_newline()