CS51: Abstraction and Design in Computation
Stuart M. Shieber
Now playing: “Living With Substitutions” Stephan Panev Living With Substitutions
John A. Paulson School of Engineering and Applied Sciences 1 Harvard University 7: The substitution model
2 Big ideas
The informal semantics of OCaml can be made more rigorous through the substitution model of evaluation. The substitution model can be made explicit in a metacircular interpreter. Rigorous semantics is easier to provide for smaller languages The lambda calculus, the core of OCaml, is very small indeed yet computationally universal
3 The substitution model: Arithmetic and let...in binding
4 From OCaml expressions lecture 2...
expr ::= value numbers, strings, bools, etc. | id variables (x, foo, etc.)
| expr1 binop expr2 binary operators (3 + 4)
| expr1 expr2 function application (foo 42)
| let id = expr1 in expr2 local naming
| if expr1 then expr2 else expr3 conditional | fun id -> expr anonymous functions
5 OCaml expressions
expr ::= value numbers, strings, bools, etc. | id variables (x, foo, etc.)
| expr1 binop expr2 binary operators (3 + 4)
| expr1 expr2 function application (foo 42)
| let id = expr1 in expr2 local naming
| if expr1 then expr2 else expr3 conditional | fun id -> expr anonymous functions
6 Evaluation: values
3 ⟹ 3 To evaluate m: Result is m 4 ⟹ 4
5 ⟹ 5
7 Evaluation: binary operators
3 + (4 * 5) To evaluate P + Q: 3 ⟹ 3 Evaluate P to m Evaluate Q to n Result is m+n
8 Evaluation: binary operators
3 + (4 * 5) To evaluate P + Q: 3 ⟹ 3 Evaluate P to m 4 * 5 4 ⟹ 4 Evaluate Q to n 5 ⟹ 5 Result is m+n
9 Evaluation: binary operators
3 + (4 * 5) To evaluate P + Q: 3 ⟹ 3 Evaluate P to m 4 * 5 4 ⟹ 4 Evaluate Q to n 5 ⟹ 5 Result is m+n ⟹ 20
10 Evaluation: binary operators
3 + (4 * 5) To evaluate P + Q: 3 ⟹ 3 Evaluate P to m 4 * 5 4 ⟹ 4 Evaluate Q to n 5 ⟹ 5 Result is m+n ⟹ 20 ⟹ 23
11 Evaluation: let...in expressions
let x = 3 in x*x To evaluate let x = Q in P: Evaluate Q to Q' Evaluate P[x ↦ Q'] to R Result is R
12 Evaluation: let...in expressions
let x = 3 in x*x To evaluate let x = Q in P: Evaluate Q to Q' Evaluate P[x ↦ Q'] to R Result is R
P[x ↦ Q] means substitute Q for (appropriate) x in P
12 Evaluation: let...in expressions
let x = 3 in x*x To evaluate 3 ⟹ 3 let x = Q in P: Evaluate Q to Q' Evaluate P[x ↦ Q'] to R Result is R
P[x ↦ Q] means substitute Q for (appropriate) x in P
13 Evaluation: let...in expressions
let x = 3 in x*x To evaluate 3 ⟹ 3 let x = Q in P: 3 * 3 3 ⟹ 3 Evaluate Q to Q' 3 ⟹ 3 Evaluate P[x ↦ Q'] to R ⟹ 9 Result is R
P[x ↦ Q] means substitute Q for (appropriate) x in P
14 Evaluation: let...in expressions
let x = 3 in x*x To evaluate 3 ⟹ 3 let x = Q in P: 3 * 3 3 ⟹ 3 Evaluate Q to Q' 3 ⟹ 3 Evaluate P[x ↦ Q'] to R ⟹ 9 Result is R ⟹ 9 P[x ↦ Q] means substitute Q for (appropriate) x in P
15 The indiscernibility of identicals
That A is the same as B signifies that the one can be substituted for the other, salva veritate, in any proposition whatever. – Gottfried Wilhelm Leibniz
Gottfried Wilhelm Leibniz
16 Implementing arithmetic evaluation
type expr = | Int of int | Var of varspec | Binop of binop * expr * expr | Let of varspec * expr * expr and binop = Plus | Times and varspec = string ;;
17 find this code in: eval_arith.ml Implementing arithmetic evaluation
let x = 3 in Let("x", let y = 5 in Int 3, x * y Let ("y", Int 5, Binop(Times, Var "x", Var "y")))
Concrete syntax Abstract syntax (as represented in OCaml) (as represented in OCaml) 18 Implementing arithmetic evaluation
let x = 3 in Let let y = 5 in "x" Int Let x * y 3 "y" Int Binop
5 Times Var Var
"x" "y"
Concrete syntax Abstract syntax (as represented in OCaml) (as represented in OCaml) 19 Implementing arithmetic evaluation
type expr = | Int of int | Var of varspec | Binop of binop * expr * expr | Let of varspec * expr * expr and binop = Plus | Times and varspec = string ;;
20 find this code in: eval_arith.ml Implementing arithmetic evaluation
type expr =
| Int of int This represents the | Var of varspec occurrence of a variable, a | Binop of binop * expr *free expr occurrence unless | Let of varspec * expr *bound expr by a let binder. and binop = Plus | Times and varspec = string ;;
20 find this code in: eval_arith.ml Implementing arithmetic evaluation
type expr = | Int of int | Var of varspec | Binop of binop * expr * expr | Let of varspec * expr * expr and binop = Plus | Times and varspecThe Let = stringbinds all free;; occurrences of its variable in its scope.
20 find this code in: eval_arith.ml Implementing arithmetic evaluation
let rec eval (e : expr) : expr = match e with | Int i -> ???
21 Implementing arithmetic evaluation
let rec eval (e : expr) : expr = match e with | Int _ -> e | Binop (op, e1, e2) -> ???
22 Implementing arithmetic evaluation
let rec eval (e : expr) : expr = match e with | Int _ -> e Integers are values; they self-evaluate | Binop (op, e1, e2) -> ???
22 Implementing arithmetic evaluation
let rec eval (e : expr) : expr = match e with | Int _ -> e | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2)
23 Implementing arithmetic evaluation
let rec eval (e : expr) : expr = match e with | Int _ -> e | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2)
We'll assume a function that performs the arithmetic dependent on the operation...
23 Implementing arithmetic evaluation
let rec eval (e : expr) : expr = match e with | Int _ -> e ...and the evaluated arguments | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2)
We'll assume a function that performs the arithmetic dependent on the operation...
23 Implementing arithmetic evaluation
let binopeval (op : binop) (v1 : expr) (v2 : expr) : expr = match op, v1, v2 with | Plus, Int x1, Int x2 -> Int (x1 + x2) | Plus, _, _ -> raise (IllFormed "can't add non-ints") | Times, Int x1, Int x2 -> Int (x1 * x2) | Times, _, _ -> raise (IllFormed "can't mult non-ints") ;;
24 Implementing arithmetic evaluation
let binopeval (op : binop) (v1 : expr) (v2 : expr) : expr = match op, v1, v2 with | Plus, Int x1, Int x2 -> Int (x1 + x2) | Plus, _, _ -> raise (IllFormed "can't add non-ints") | Times, Int x1, Int x2 -> Int (x1 * x2) | Times, _, _ -> raise (IllFormed "can't mult non-ints") ;;
24 Implementing arithmetic evaluation
let rec eval (e : expr) : expr = match e with | Int _ -> e | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2) | Let (x, def, body) -> ???
25 Implementing arithmeticTo evaluate evaluation let x = Q in P:
let rec eval (e : expr) Evaluate: expr = Q to Q' match e with Evaluate P[x ↦ Q'] to R | Int _ -> e Result is R | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2) | Let (x, def, body) -> ???
25 Implementing arithmeticTo evaluate evaluation let x = Q in P:
let rec eval (e : expr) Evaluate: expr = Q to Q' match e with Evaluate P[x ↦ Q'] to R | Int _ -> e Result is R | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2) | Let (x, def, body) -> eval (subst body x (eval def))
26 Implementing arithmeticTo evaluate evaluation let x = Q in P:
let rec eval (e : expr) Evaluate: expr = Q to Q' match e with Evaluate P[x ↦ Q'] to R | Int _ -> e Result is R | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2) | Let (x, def, body) -> eval (subst body x (eval def))
The subst p x q function implements P[x ↦ Q]
26 Implementing arithmetic evaluation
let rec eval (e : expr) : expr = match e with | Int _ -> e | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2) | Let (x, def, body) -> eval (subst body x (eval def)) | Var x -> ???
27 find this code in: eval_arith.ml Implementing arithmetic evaluation
let rec eval (e : expr) : expr = match e with | Int _ -> e | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2) | Let (x, def, body) -> eval (subst body x (eval def)) | Var x -> raise (UnboundVariable x) ;;
28 find this code in: eval_arith.ml Implementing arithmetic evaluation
let rec eval (e : expr) : expr = match e with | Int _ -> e | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2) | Let (x, def, body) -> eval (subst body x (eval def)) | Var x -> raise (UnboundVariable x) ;;
We should never come across an unsubstituted variable.
28 find this code in: eval_arith.ml Implementing arithmetic evaluation
let rec eval (e : expr) : expr = match e with | Int _ -> e | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2) | ... let binopeval op v1 v2 = match op, v1, v2 with | Plus, Int x1, Int x2 -> Int (x1 + x2) | ...
29 find this code in: eval_arith.ml ImplementingAn interpreter arithmetic for OCaml evaluation (or a subset) that...
let rec eval (e : expr) : expr = match e with | Int _ -> e | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2) | ... let binopeval op v1 v2 = match op, v1, v2 with | Plus, Int x1, Int x2 -> Int (x1 + x2) | ...
29 find this code in: eval_arith.ml ImplementingAn interpreter arithmetic for OCaml evaluation (or a subset) that...
let rec eval (e : expr) : expr = match e with | Int _ -> e | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2) | ... let binopeval op v1 v2...uses = OCaml constructs in the metalanguage... match op, v1, v2 with | Plus, Int x1, Int x2 -> Int (x1 + x2) | ...
29 find this code in: eval_arith.ml ImplementingAn interpreter arithmetic for OCaml evaluation (or a subset) that...
let rec eval (e : expr) : expr = match e with | Int _ -> e | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2) | ... let binopeval op v1 v2...uses = OCaml constructs in the metalanguage... match op, v1, v2 with | Plus, Int x1, Int x2 -> Int (x1 + x2) | ...... to circularly manifest OCaml
29 constructs in the object languagefind this code in: eval_arith.ml ImplementingAn interpreter arithmetic for OCaml evaluation (or a subset) that...
let rec eval (e : expr) : expr = match e with | Int _ -> e A metacircular | Binop (op, e1, e2) -> interpreter binopeval op (eval e1) (eval e2) | ... let binopeval op v1 v2...uses = OCaml constructs in the metalanguage... match op, v1, v2 with | Plus, Int x1, Int x2 -> Int (x1 + x2) | ...... to circularly manifest OCaml
30 constructs in the object languagefind this code in: eval_arith.ml Implementing arithmetic evaluation
let rec eval (e : expr) : expr = match e with | Int _ -> e | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2) | Let (x, def, body) -> eval (subst body x (eval def)) | Var x -> raise (UnboundVariable x) ;;
31 find this code in: eval_arith.ml Free and bound variables
x * y
32 Free and bound variables
x * y
free
32 Free and bound variables
x * y
free free
32 Free and bound variables
x * y
free free let y = 5 in x * y
32 Free and bound variables
x * y
free free let y = 5 in x * y
free
32 Free and bound variables
x * y
free free let y = 5 in x * y
free bound
32 Free and bound variables
x * y
free free let y = 5 in x * y
free bound let x = 3 in let y = 5 in x * y
32 Free and bound variables
x * y
free free let y = 5 in x * y
free bound let x = 3 in let y = 5 in x * y
bound
32 Free and bound variables
x * y
free free let y = 5 in x * y
free bound let x = 3 in let y = 5 in x * y
bound bound
32 Free and bound variables
x * y
free free let y = 5 in x * y
free bound let y = 3 in let y = 5 in x * y
33 Free and bound variables
x * y
free free let y = 5 in x * y
free bound let y = 3 in let y = 5 in x * y
bound
33 Free and bound variables
x * y
free free let y = 5 in x * y
free bound let y = 3 in let y = 5 in x * y
bound
33 Free and bound variables
x * y
free free let y = 5 in x * y
free bound let y = 3 in let y = 5 in x * y
free bound
33 Free and bound variables
let x = 3 in let y = x + 3 in x * y
34 Free and bound variables
let x = 3 in let y = x + 3 in x * y
bound
34 Free and bound variables
let x = 3 in let y = x + 3 in x * y
free bound
34 Free and bound variables
let x = 3 in let y = x + 3 in x * y free
free bound
34 Free and bound variables
let x = 3 in let y = x + 3 in x * y
35 Free and bound variables
let x = 3 in let y = x + 3 in x * y
bound
35 Free and bound variables
let x = 3 in let y = x + 3 in x * y bound bound bound
35 Implementing arithmetic evaluation
let rec eval (e : expr) : expr = match e with | Int _ -> e | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2) | Let (x, def, body) -> eval (subst body x (eval def)) | Var x -> raise (UnboundVariable x) ;;
36 Implementing arithmetic evaluation
let rec eval (e : expr) : expr = match e with | Int _ -> e | Binop (op, e1, e2) -> binopeval op (eval e1) (eval e2) | Let (x, def, body) -> eval (subst body x (eval def)) | Var x -> raise (UnboundVariable x) ;;
Careful! We must replace only free occurrences of x in body.
36 Implementing substitution
let rec subst (p : expr) (x : varspec) (q : expr) : expr = match p with | Int _ -> ???
37 Implementing substitution
let rec subst (p : expr) (x : varspec) (q : expr) : expr = match p with | Int _ -> p Don’t touch the integers. | Var y -> ???
38 Implementing substitution
let rec subst (p : expr) (x : varspec) (q : expr) : expr = match p with Substitute for x, not any other y. | Int _ -> p | Var y -> if y = x then q else p | Binop (op, e1, e2) -> ???
39 Implementing substitution
let rec subst (p : expr) (x : varspec) (q : expr) : expr = match p with | Int _ -> p Substitute recursively | Var y -> if y = throughoutx then q elsethe tree. p | Binop (op, e1, e2) -> Binop (op, subst e1 x q, subst e2 x q) | Let (y, def, body) -> ???
40 Implementing substitution
let rec subst (p : expr) (x : varspec) (q : expr) : expr = match p with | Int _ -> p | Var y -> if y = x then q else p | Binop (op, e1,Substitute e2) -> recursively Binop (op, substthroughout e1 xthe q, tree. subst e2 x q) | Let (y, def, body) -> Let (y, subst def x q, subst body x q) ;;
41 find this code in: eval_arith.ml Implementing substitution
let subst (p : expr) (x : varspec) (q : expr) : expr = let rec subst' p = match p with | Int _ -> p | Var y -> if y = x then q else p | Binop (op, e1, e2) -> Binop (op, subst' e1, subst' e2) | Let (y, def, body) -> Let (y, subst' def, subst' body) in subst' p ;;
42 find this code in: eval_arith.ml # let x = 3 in x * x ;; OCaml interpreter OCaml
43 # let x = 3 in x * x ;; - : int = 9 OCaml interpreter OCaml
44 # let x = 3 in x * x ;; - : int = 9 OCaml interpreter OCaml
# eval (Let("x", Int 3, Binop(Times, Var "x", Var "x"))) ;; - : expr = Int 9 # Metacircular interpreter Metacircular
45 # let x = 3 in let y = 5 in x * y ;; OCaml interpreter OCaml Metacircular interpreter Metacircular
46 # let x = 3 in let y = 5 in x * y ;; - : int = 15 OCaml interpreter OCaml Metacircular interpreter Metacircular
47 # let x = 3 in let y = 5 in x * y ;; - : int = 15 OCaml interpreter OCaml
# eval (Let("x", Int 3, Let ("y", Int 5, Binop(Times, Var "x", Var "y")))) ;; - : expr = Int 15 # Metacircular interpreter Metacircular
48 # let x = 3 in let x = 5 in x * x ;; OCaml interpreter OCaml Metacircular interpreter Metacircular
49 # let x = 3 in let x = 5 in x * x ;; - : int = 25 OCaml interpreter OCaml Metacircular interpreter Metacircular
50 # let x = 3 in let x = 5 in x * x ;; - : int = 25 OCaml interpreter OCaml
# eval (Let("x", Int 3, Let ("x", Int 5, Binop(Times, Var "x", Var "x")))) ;; - : expr = Int 9 # Metacircular interpreter Metacircular
51 Implementing substitution
let subst (p : expr) (x : varspec) (q : expr) : expr =
let rec subst' p = Warning match p with CS51 project | Int _ -> p | Var y -> if y = x then q else p | Binop (op, e1, e2) -> Binop (op, subst' e1, subst' e2) | Let (y, def, body) -> Let (y, subst' def, subst' body) in subst' p ;;
52 find this code in: eval_arith.ml Implementing substitution
let subst (p: expr) (x: varspec) (q: expr) : expr = let rec subst' p = match p with | Int _ -> p If x = y then this | LetVar bindsy -> allif ofy the= xfree then occurrences q else inp the body soThis | don't Binop Let substitute binds (op, all e1,of in the the e2) free body. -> occurrences in the body. Binop (op, subst' e1, subst' e2) | Let (y, def, body) -> if x = y then Let (y, subst' def, body) else Let (y, subst' def, subst' body) in subst' p ;;
53 find this code in: eval_arith2.ml # let x = 3 in let x = 5 in x * x ;; - : int = 25 OCaml interpreter OCaml
# eval (Let("x", Int 3, Let ("x", Int 5, Binop(Times, Var "x", Var "x")))) ;; - : expr = Int 25 # Metacircular interpreter Metacircular
54 The substitution model: Functions and application
55 OCaml expressions
expr ::= value numbers, strings, bools, etc. | id variables (x, foo, etc.)
| expr1 binop expr2 binary operators (3 + 4)
| expr1 expr2 function application (foo 42)
| let id = expr1 in expr2 local naming
| if expr1 then expr2 else expr3 conditional | fun id -> expr anonymous functions
56 Evaluation: functions are values
3 ⟹ 3 To evaluate m: Result is m
fun x -> (1+2)*x To evaluate (fun x -> B): ⟹ Result is (fun x -> B) fun x -> (1+2)*x
57 Evaluation: function applications
(fun x->x*x) (1+2) To evaluate P Q: (fun x->x*x) Evaluate P to ⟹ (fun x->x*x) 1+2 (fun x -> B) 1 ⟹ 1 Evaluate Q to Q' 2 ⟹ 2 Evaluate B[x ↦ Q'] to R ⟹ 3 Result is R 3*3 ⟹ 9 ⟹ 9 Substitution again
58 Evaluation: let...in expressions
let x = 3 in x*x To evaluate (fun x->x*x) 3 let x = Q in P: (fun x->x*x) ⟹ (fun x->x*x) Evaluate 3*3 ⟹ 9 (fun x -> P) Q ⟹ 9 to R Result is R
We can turn let binding into function application
59 Evaluation: let...in expressions
To evaluate To evaluate let x = Q in P: let x = Q in P: Evaluate Evaluate (fun x -> P) to (fun x -> P) Q (fun x -> B) to R Evaluate Q to Q' Result is R Evaluate B[x ↦ Q'] to R Result is R
60 Evaluation: let...in expressions
To evaluate To evaluate let x = Q in P: let x = Q in P: Evaluate Q to Q' Evaluate Evaluate P[x ↦ Q'] to R (fun x -> P) Q Result is R to R Result is R
61 Another OCaml subset
expr ::= value numbers, strings, bools, etc. | id variables (x, foo, etc.)
| expr1 binop expr2 binary operators (3 + 4)
| expr1 expr2 function application (foo 42)
| let id = expr1 in expr2 local naming
| if expr1 then expr2 else expr3 conditional | fun id -> expr anonymous functions
62 The lambda calculus
Lambda calculus OCaml Variables x x Application P Q P Q Abstraction λx. P (fun x -> P)
63 The lambda calculus
Lambda calculus OCaml Variables x x Application P Q P Q
Alonzo Church Abstraction λx. P (fun x -> P)
63 The lambda calculus: OCaml’s core
Lambda calculus OCaml Variables x x Application P Q P Q
Alonzo Church Abstraction λx. P (fun x -> P)
64 Representing numbers as functions
Church numerals 0 (fun x -> (fun y -> y)) 1 (fun x -> (fun y -> x y)) 2 (fun x -> (fun y -> x (x y))) n (fun x -> (fun y -> xn y)) +1 (fun n -> (fun x -> (fun y -> x (n x y)))) + (fun m -> (fun n -> (m (+1) n)))
65 An example: +1 1
Church numerals
0 (fun x -> (fun y -> y))
1 (fun x -> (fun y -> x y))
2 (fun x -> (fun y -> x (x y))) n (fun x -> (fun y -> xn y))
+1 (fun n -> (fun x -> (fun y -> x (n x y))))
+ (fun m -> (fun n -> (m (+1) n)))
+1 1 = (fun n -> (fun x -> (fun y -> x (n x y)))) (fun x -> (fun y -> x y)) ⇒ (fun x -> (fun y -> x ((fun x' -> (fun y' -> x' y')) x y)))
⇒ (fun x -> (fun y -> x ((fun y' -> x y')) y))
⇒ (fun x -> (fun y -> x (x y)))
= 2
66 An example: +1 1
# let zero = (fun x -> (fun y -> y));; val zero : 'a -> 'b -> 'b =
67 An example: +1 1
# let zero = (fun x -> (fun y -> y));; val zero : 'a -> 'b -> 'b =
68 An example: 2 + 2 add two two ⇒ (fun m -> (fun n -> m add1 n)) two two ⇒ two add1 two ⇒ (fun x -> (fun y -> x (x y))) add1 two ⇒ add1 (add1 two) ⇒ add1 ((fun n -> (fun x -> (fun y -> x (n x y)))) two) ⇒ add1 (fun x -> (fun y -> x (two x y))) ⇒ add1 (fun x -> (fun y -> x ((fun x' -> (fun y' -> x' (x' y'))) x y))) ⇒ add1 (fun x -> (fun y -> x (x (x y)))) ⇒ (fun n -> (fun x -> (fun y -> x (n x y)))) (fun x -> (fun y -> x (x (x y)))) ⇒ (fun x -> (fun y -> x ((fun x' -> (fun y' -> x' (x' (x' y')))) x y))) ⇒ (fun x -> (fun y -> x (x (x (x y))))) = 4 69 An example: 2 + 2
# let two = add1 (add1 zero);; val two : ('_a -> '_a) -> '_a -> '_a =
70 An example: 2 + 2
% ./miniml.byte <== let out = fun x -> x (fun y -> (y + 1)) 0 in let zero = (fun x -> (fun y -> y)) in let add1 = (fun n -> (fun x -> (fun y -> x (n x y)))) in out (add1 zero) ;; ==> 1 <== let out = fun x -> x (fun y -> (y + 1)) 0 in let zero = (fun x -> (fun y -> y)) in let add1 = (fun n -> (fun x -> (fun y -> x (n x y)))) in let add = (fun m -> (fun n -> m add1 n)) in let two = add1 (add1 zero) in let add = (fun m -> (fun n -> m add1 n)) in let four = add two two in out four ;; ==> 4
71 Representing conditionals
Church numerals: 0 (fun x -> (fun y -> y)) 1 (fun x -> (fun y -> x y)) 2 (fun x -> (fun y -> x (x y))) n (fun x -> (fun y -> xn y)) +1 (fun n -> (fun x -> (fun y -> x (n x y)))) + (fun m -> (fun n -> (m (+1) n))) Church conditionals: true (fun x -> (fun y -> x)) false (fun x -> (fun y -> y)) if (fun cond -> (fun then -> (fun else -> cond then else))) is0 (fun x -> x (fun y -> false) true) 72 An example: if is0 1 then 0 else 1
73 An example: if is0 1 then 0 else 1
% ./miniml_soln.byte <== let out = fun x -> x (fun y -> (y + 1)) 0 in let zero = (fun x -> (fun y -> y)) in let add1 = (fun n -> (fun x -> (fun y -> x (n x y)))) in let tru = (fun x -> (fun y -> x)) in let fal = (fun x -> (fun y -> y)) in let ifx = (fun i -> (fun t -> (fun e -> i t e))) in let is0 = (fun x -> x (fun y -> fal) tru) in out (ifx (is0 (add1 zero)) zero (add1 zero)) ;; ==> 1 <==
73 Implementing the lambda calculus
type expr = | Var of varspec | Fun of varspec * expr | App of expr * expr and varspec = string ;;
74 find this code in: eval_church.ml Implementing the lambda calculus
let rec subst (p : expr) (x : varspec) Warning (q : expr) : expr = CS51 project match p with | Var y -> if y = x then q else p | App (e1, e2) -> App (subst e1 x q, subst e2 x q) | Fun (y, body) -> if x = y then p else Fun(y, subst body x q) ;;
75 find this code in: eval_church.ml Implementing the lambda calculus
let rec eval (e : expr) : expr = match e with | Var _ -> e | Fun (_, _) -> e | App (f, q) -> match eval f with | Fun(x, p) -> eval (subst p x (eval q)) | _ -> e ;;
76 find this code in: eval_church.ml Implementing the lambda calculus
let zero = Fun("x", Fun("y", Var "y")) ;; let add1 = Fun("n", Fun("x", Fun("y", App(Var "x", App(App(Var "n", Var "x"), Var "y")))));; let cfalse = Fun("x", Fun("y", Var "y")) ;; let ctrue = Fun("x", Fun("y", Var "x")) ;; let cif = Fun("cond", Fun("then", Fun("else", App(App(Var "cond", Var "then"), Var "else")))) ;; let is0 = Fun ("n", App(App(Var "n", Fun("y", cfalse)), ctrue)) ;; (* if is0 (+1 0) then +1 0 else 0 *) let test = App(App(App(cif, App(is0, App(add1, zero))), App(add1, zero)), zero) ;;
77 find this code in: eval_church.ml # test ;; - : expr = if is0 (+1 0) App then +1 0 (App (App else 0 (Fun ("cond", Fun ("then", Fun ("else", App (App (Var "cond", Var "then"), Var "else")))), App (Fun ("n", App (App (Var "n", Fun ("y", Fun ("x", Fun ("y", Var "y")))), Fun ("x", Fun ("y", Var "x")))), App (Fun ("n", Fun ("x", Fun ("y", App (Var "x", App (App (Var "n", Var "x"), Var "y"))))), Fun ("x", Fun ("y", Var "y"))))), App (Fun ("n", Fun ("x", Fun ("y", App (Var "x", App (App (Var "n", Var "x"), Var "y"))))), Fun ("x", Fun ("y", Var "y")))), Fun ("x", Fun ("y", Var "y"))) # eval test ;; - : expr = Fun ("x", Fun ("y", Var "y"))
78 From OCaml expressions lecture 2...
expr ::= value numbers, strings, bools, etc. | id variables (x, foo, etc.)
| expr1 binop expr2 binary operators (3 + 4)
| expr1 expr2 function application (foo 42)
| let id = expr1 in expr2 local naming
| if expr1 then expr2 else expr3 conditional | fun id -> expr anonymous functions
79 Big ideas
The informal semantics of OCaml can be made more rigorous through the substitution model of evaluation. The substitution model can be made explicit in a metacircular interpreter. Rigorous semantics is easier to provide for smaller languages The lambda calculus, the core of OCaml, is very small indeed yet computationally universal
80