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 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 , 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 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 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 = # let add1 = (fun n -> (fun x -> (fun y -> x (n x y))));; val add1 : (('a -> 'b) -> 'c -> 'a) -> ('a -> 'b) -> 'c - > 'b = # let two = add1 (add1 zero);; val two : ('_a -> '_a) -> '_a -> '_a = # let out n = n ((+) 1) 0;; val out : ((int -> int) -> int -> 'a) -> 'a = # to_string two;; - : int = 2 #

67 An example: +1 1

# let zero = (fun x -> (fun y -> y));; val zero : 'a -> 'b -> 'b = # let add1 = (fun n -> (fun x -> (fun y -> x (n x y))));; val add1 : (('a -> 'b) -> 'c -> 'a) -> ('a -> 'b) -> 'c - > 'b = # let two = add1 (add1 zero);; val two : ('_a -> '_a) -> '_a -> '_a = # let out n = n ((+) 1) 0;; val out : ((int -> int) -> int -> 'a) -> 'a = # out two;; - : int = 2 #

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 = # let add = (fun m -> (fun n -> m add1 n));; val add : (((('a -> 'b) -> 'c -> 'a) -> ('a -> 'b) -> 'c -> 'b) -> 'd -> 'e) -> 'd -> 'e = # let four = add two two;; Error: This has type (int -> int) -> int -> int but an expression was expected of type ((('a -> 'b) -> 'c -> 'a) -> ('a -> 'b) -> 'c -> 'b) -> 'd -> 'e Type int is not compatible with type ('a -> 'b) -> 'c -> '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