1 Formal Semantics. 2 Why formalize? ML is tricky, particularly in corner cases generalizable type variables? polymorphic references? exceptions? Some.

Slides:



Advertisements
Similar presentations
Types and Programming Languages Lecture 7 Simon Gay Department of Computing Science University of Glasgow 2006/07.
Advertisements

Type Checking, Inference, & Elaboration CS153: Compilers Greg Morrisett.
Semantics Static semantics Dynamic semantics attribute grammars
Computational Models The exam. Models of computation. –The Turing machine. –The Von Neumann machine. –The calculus. –The predicate calculus. Turing.
- Vasvi Kakkad.  Formal -  Tool for mathematical analysis of language  Method for precisely designing language  Well formed model for describing and.
The lambda calculus David Walker CS 441. the lambda calculus Originally, the lambda calculus was developed as a logic by Alonzo Church in 1932 –Church.
ISBN Chapter 3 Describing Syntax and Semantics.
CS 355 – Programming Languages
Compiler Construction
Catriel Beeri Pls/Winter 2004/5 last 55 Two comments on let polymorphism I. What is the (time, space) complexity of type reconstruction? In practice –
Comp 205: Comparative Programming Languages Semantics of Imperative Programming Languages denotational semantics operational semantics logical semantics.
1 Introduction to Computability Theory Lecture12: Reductions Prof. Amos Israeli.
Foundations of Programming Languages: Introduction to Lambda Calculus
1 Operational Semantics Mooly Sagiv Tel Aviv University Textbook: Semantics with Applications.
1 Formal Semantics. 2 Why formalize? ML is tricky, particularly in corner cases generalizable type variables? polymorphic references? exceptions? Some.
1 Amazing fact #3: -calculus is Turing-complete! But the -calculus is too weak, right? No multiple arguments! No numbers or arithmetic! No booleans or.
7. Fixed Points. © O. Nierstrasz PS — Fixed Points 7.2 Roadmap  Representing Numbers  Recursion and the Fixed-Point Combinator  The typed lambda calculus.
Chair of Software Engineering 1 Concurrent Object-Oriented Programming Arnaud Bailly, Bertrand Meyer and Volkan Arslan.
Describing Syntax and Semantics
1 Formal Semantics. 2 Why formalize? ML is tricky, particularly in corner cases generalizable type variables? polymorphic references? exceptions? Some.
Chapter 2 Syntax A language that is simple to parse for the compiler is also simple to parse for the human programmer. N. Wirth.
CMSC 330: Organization of Programming Languages Lambda Calculus Introduction λ.
Functional Programming Universitatea Politehnica Bucuresti Adina Magda Florea
CSE S. Tanimoto Lambda Calculus 1 Lambda Calculus What is the simplest functional language that is still Turing complete? Where do functional languages.
© Kenneth C. Louden, Chapter 11 - Functional Programming, Part III: Theory Programming Languages: Principles and Practice, 2nd Ed. Kenneth C. Louden.
Typed Lambda Calculus Chapter 9 Benjamin Pierce Types and Programming Languages.
Chapter Twenty-ThreeModern Programming Languages1 Formal Semantics.
ISBN Chapter 3 Describing Semantics -Attribute Grammars -Dynamic Semantics.
CS 363 Comparative Programming Languages Semantics.
Formal Semantics Chapter Twenty-ThreeModern Programming Languages, 2nd ed.1.
Lesson 4 Typed Arithmetic Typed Lambda Calculus 1/21/02 Chapters 8, 9, 10.
1 ML fun x -> e e 1 e 2 0, 1, 2,..., +, -,... true, false, if e then e else e patterns datatypes exceptions structures functors let f x = e variables These.
© Kenneth C. Louden, Chapter 11 - Functional Programming, Part III: Theory Programming Languages: Principles and Practice, 2nd Ed. Kenneth C. Louden.
CSE 230 The -Calculus. Background Developed in 1930’s by Alonzo Church Studied in logic and computer science Test bed for procedural and functional PLs.
3.2 Semantics. 2 Semantics Attribute Grammars The Meanings of Programs: Semantics Sebesta Chapter 3.
Chapter 3 Part II Describing Syntax and Semantics.
Programming Languages and Design Lecture 3 Semantic Specifications of Programming Languages Instructor: Li Ma Department of Computer Science Texas Southern.
Semantics In Text: Chapter 3.
Semantic Analysis Semantic Analysis v Lexically and syntactically correct programs may still contain other errors v Lexical and syntax analyses.
1 Formal Semantics. 2 Why formalize? ML is tricky, particularly in corner cases generalizable type variables? polymorphic references? exceptions? Some.
Types and Programming Languages Lecture 12 Simon Gay Department of Computing Science University of Glasgow 2006/07.
12/9/20151 Programming Languages and Compilers (CS 421) Elsa L Gunter 2112 SC, UIUC Based in part on slides by Mattox.
1 / 48 Formal a Language Theory and Describing Semantics Principles of Programming Languages 4.
CSE 413 Languages & Implementation Hal Perkins Autumn 2012 Structs, Implementing Languages (credits: Dan Grossman, CSE 341) 1.
-Calculus Kangwon National University 임현승 Programming Languages These slides are based on the slides by Prof. Sungwoo Park at POSTECH.
Advanced Formal Methods Lecture 3: Simply Typed Lambda calculus Mads Dam KTH/CSC Course 2D1453, Some material from B. Pierce: TAPL + some from.
Types and Programming Languages Lecture 11 Simon Gay Department of Computing Science University of Glasgow 2006/07.
CMSC 330: Organization of Programming Languages Operational Semantics a.k.a. “WTF is Project 4, Part 3?”
Fall 2008Programming Development Techniques 1 Topic 17 Assignment, Local State, and the Environment Model of Evaluation Section 3.1 & 3.2.
Semantic Analysis II Type Checking EECS 483 – Lecture 12 University of Michigan Wednesday, October 18, 2006.
CMSC 330: Organization of Programming Languages Lambda Calculus and Types.
CS412/413 Introduction to Compilers Radu Rugina Lecture 13 : Static Semantics 18 Feb 02.
Operational Semantics Mooly Sagiv Tel Aviv University Textbook: Semantics with Applications Chapter.
COMP 412, FALL Type Systems II C OMP 412 Rice University Houston, Texas Fall 2000 Copyright 2000, Robert Cartwright, all rights reserved. Students.
CMSC 330: Organization of Programming Languages Operational Semantics.
Types and Programming Languages Lecture 3 Simon Gay Department of Computing Science University of Glasgow 2006/07.
Prof. Necula CS 164 Lecture 171 Operational Semantics of Cool ICOM 4029 Lecture 10.
Operational Semantics Mooly Sagiv Tel Aviv University Sunday Scrieber 8 Monday Schrieber.
CSE-321 Programming Languages -Calculus (II) POSTECH March 26, 2007 박성우.
CS5205Semantics1 CS5205: Foundation in Programming Languages Semantics Static Semantics Dynamic Semantics Operational Semantics Big-step Small-Step Denotational.
Operational Semantics Mooly Sagiv Reference: Semantics with Applications Chapter 2 H. Nielson and F. Nielson
Operational Semantics Mooly Sagiv Reference: Semantics with Applications Chapter 2 H. Nielson and F. Nielson
Arvind Computer Science and Artificial Intelligence Laboratory M.I.T. L03-1 September 14, 2006http:// -calculus: A Basis for.
COMP 412, FALL Type Systems C OMP 412 Rice University Houston, Texas Fall 2000 Copyright 2000, Robert Cartwright, all rights reserved. Students.
CS5205: Foundations in Programming Languages
Programming Languages and Compilers (CS 421)
CS 550 Programming Languages Jeremy Johnson
Lesson 4 Typed Arithmetic Typed Lambda Calculus
Representation, Syntax, Paradigms, Types
CSE S. Tanimoto Lambda Calculus
Presentation transcript:

1 Formal Semantics

2 Why formalize? ML is tricky, particularly in corner cases generalizable type variables? polymorphic references? exceptions? Some things are often overlooked for any language evaluation order? side-effects? errors? Therefore, want to formalize what a language's definition really is Ideally, a clear & unambiguous way to define a language Programmers & compiler writers can agree on what's supposed to happen, for all programs Can try to prove rigorously that the language designer got all the corner cases right

3 Aspects to formalize Syntax: what's a syntactically well-formed program? EBNF notation for a context-free grammar Static semantics: which syntactically well-formed programs are semantically well-formed? which programs type-check? typing rules, well-formedness judgments Dynamic semantics: what does a program evaluate to or do when it runs? operational, denotational, or axiomatic semantics Metatheory: properties of the formalization itself E.g. do the static and dynamic semantics match? i.e., is the static semantics sound w.r.t. the dynamic semantics?

4 Approach Formalizing full-sized languages is very hard, tedious many cases to consider lots of interacting features Better: boil full-sized language down into essential core, then formalize and study the core cut out as much complication as possible, without losing the key parts that need formal study hope that insights gained about core will carry back to full-sized language

5 The lambda calculus The essential core of a (functional) programming language Developed by Alonzo Church in the 1930's Before computers were invented! Outline: Untyped: syntax, dynamic semantics, cool properties Simply typed: static semantics, soundness, more cool properties Polymorphic: fancier static semantics

6 Untyped -calculus: syntax (Abstract) syntax: e ::= xvariable | x. efunction/abstraction (  fn x => e ) | e 1 e 2 call/application Freely parenthesize in concrete syntax to imply the right abstract syntax The trees described by this grammar are called term trees

7 Free and bound variables x. e binds x in e An occurrence of a variable x is free in e if it's not bound by some enclosing lambda freeVars(x)  x freeVars( x. e)  freeVars(e) – {x} freeVars(e 1 e 2 )  freeVars(e 1 )  freeVars(e 2 ) e is closed iff freeVars(e) = {}

8  -renaming First semantic property of lambda calculus: bound variables in a term tree can be renamed (properly) without affecting the semantics of the term tree  -equivalent term trees ( x 1. x 2 x 1 )   ( x 3. x 2 x 3 ) cannot rename free variables term e: e and all  -equivalent term trees Can freely rename bound vars whenever helpful

9 Evaluation:  -reduction Define what it means to "run" a lambda-calculus program by giving simple reduction/rewriting/simplification rules "e 1   e 2 " means "e 1 evaluates to e 2 in one step" One case: ( x. e 1 ) e 2   [x  e 2 ]e 1 "if you see a lambda applied to an argument expression, rewrite it into the lambda body where all free occurrences of the formal in the body have been replaced by the argument expression" Can do this rewrite anywhere inside an expression

10 Examples

11 Substitution When doing substitution, must avoid changing the meaning of a variable occurrence [x  e]x  e [x  e]y  y if x  y [x  e]( x. e 2 )  ( x. e 2 ) [x  e]( y. e 2 )  ( y. [x  e]e 2 ) if x  y andy not free in e [x  e](e 1 e 2 )  ([x  e]e 1 ) ([x  e]e 2 ) can use  -renaming to ensure "y not free in e"

12 Result of reduction To fully evaluate a lambda calculus term, simply perform  -reduction until you can't any more   *  reflexive, transitive closure of   When you can't any more, you have a value, which is a normal form of the input term Does every lambda-calculus term have a normal form?

13 Reduction order Can have several lambdas applied to an argument in one expression Each called a redex Therefore, several possible choices in reduction Which to choose? Must we do them all? Does it matter? To the final result? To how long it takes to compute? To whether the result is computed at all?

14 Two reduction orders Normal-order reduction (a.k.a. call-by-name, lazy evaluation) reduce leftmost, outermost redex Applicative-order reduction (a.k.a. call-by-value, eager evaluation) reduce leftmost, outermost redex whose argument is in normal form (i.e., is a value)

15 Amazing fact #1: Church-Rosser Theorem, Part 1 Thm. If e 1   * e 2 and e 1   * e 3, then  e 4 such that e 2   * e 4 and e 3   * e 4 Corollary. Every term has a unique normal form, if it has one No matter what reduction order is used! e1e1 e2e2 e3e3 e4e4

16 Existence of normal forms? Does every term have a normal form? Consider: ( x. x x) ( y. y y)

17 Amazing fact #2: Church-Rosser Theorem, Part 2 If a term has a normal form, then normal-order reduction will find it! Applicative-order reduction might not! Example: ( x 1. ( x 2. x 2 )) (( x. x x) ( x. x x))

18 Weak head normal form What should this evaluate to? ( y. ( x. x x) ( x. x x)) Normal-order and applicative-order evaluation run forever But in regular languages, wouldn't evaluate the function's body until we called it "Head" normal form doesn't evaluate arguments until function expression is a lambda "Weak" evaluation doesn't evaluate under lambda With these alternative definitions of reduction: Reduction terminates on more lambda terms Correspond more closely to real languages (particularly "weak")

19 Amazing fact #3: -calculus is Turing-complete! But the -calculus is too weak, right? No multiple arguments! No numbers or arithmetic! No booleans or if! No data structures! No loops or recursion!

20 Multiple arguments: currying Encode multiple arguments via curried functions, just as in regular ML (x 1, x 2 ). e  x 1. ( x 2. e) (  x 1 x 2. e) f(e 1, e 2 )  (f e 1 ) e 2

21 Church numerals Encode natural numbers using stylized lambda terms zero  s. z. z one  s. z. s z two  s. z. s (s z) … n  s. z. s n z A unary encoding using functions No stranger than binary encoding

22 Arithmetic on Church numerals Successor function: take (the encoding of) a number, return (the encoding of) its successor I.e., add an s to the argument's encoding succ  n. s. z. s (n s z) succ zero   s. z. s (zero s z)   * s. z. s z = one succ two   s. z. s (two s z)   * s. z. s (s (s z)) = three

23 Addition To add x and y, apply succ to y x times Key idea: x is a function that, given a function and a base, applies the function to the base x times "a number is as a number does" plus  x. y. x succ y plus two three   * two succ three   * succ (succ three) = five Multiplication is repeated addition, similarly

24 Booleans Key idea: true and false are encoded as functions that do different things to their arguments, i.e., make a choice if  b. t. e. b t e true  t. e. t false  t. e. e if false four six   * false four six   * six

25 Combining numerals & booleans To complete Peano arithmetic, need an isZero predicate Key idea: call the argument number on a successor function that always returns false (not zero) and a base value that's true (is zero) isZero  n. n ( x. false) true isZero zero   * zero ( x. false) true   * true isZero two   * two ( x. false) true   * ( x. false) (( x. false) true)   * false

26 Data structures Try to encode simple pairs Can build more complex data structures out of them Key idea: a pair is a function that remembers its two input values, and passes them to a client function on demand First and second are client functions that just return one or the other remembered value mkPair  f. s. x. x f s first  p. p ( f. s. f) second  p. p ( f. s. s) second (mkPair true four)   * second ( x. x true four)   * ( x. x true four) ( f. s. s)   * ( f. s. s) true four   * four

27 Loops and recursion -calculus can write infinite loops E.g. ( x. x x) ( x. x x) What about useful loops? I.e., recursive functions? Ill-defined attempt: fact  n. if (isZero n) one (times n (fact (minus n one))) Recursive reference isn't defined in our simple short-hand notation We're trying to define what recursion means!

28 Amazing fact #N: Can define recursive funs non-recursively! Step 1: replace the bogus self-reference with an explicit argument factG  f. n. if (isZero n) one (times n (f (minus n one))) Step 2: use the paradoxical Y combinator to "tie the knot" fact  Y factG Now all we need is a magic Y that makes its non-recursive argument act like a recursive function…

29 Y combinator A definition of Y: Y  f. ( x. f (x x)) ( x. f (x x)) When applied to a function f: Y f   ( x. f (x x)) ( x. f (x x))   f (( x. f (x x)) ( x. f (x x))) = f (Y f)   * f (f (Y f))   * f (f (f (Y f)))   * … Applies its argument to itself as many times as desired "Computes" the fixed point of f Often called fix

30 Y for factorial fact two   * (Y factG) two   * factG (Y factG) two   * if (isZero two) one (times two ((Y factG) (minus two one)))   * times two ((Y factG) one)   * times two (factG (Y factG) one)   * times two (if (isZero one) one (times one ((Y factG) (minus one one))))   * times two (times one ((Y factG) zero))   * times two (times one (factG (Y factG) zero))   * times two (times one (if (isZero zero) one (times zero ((Y factG) (minus zero one)))))   * times two (times one one)   * two

31 Some intuition (?) Y passes a recursive call of a function to the function Will lead to infinite reduction, unless one recursive call chooses to ignore its recursive function argument I.e., have a base case that's not defined recursively Relies on normal-order evaluation to avoid evaluating the recursive call argument until needed

32 Summary, so far Saw untyped -calculus syntax Saw some rewriting rules, which defined the semantics of -terms  -renaming for changing bound variable names  -reduction for evaluating terms Normal form when no more evaluation possible Normal-order vs. applicative-order strategies Saw some amazing theorems Saw the power of -calculus to encode lots of higher-level constructs

33 Simply-typed lambda calculus Now, let's add static type checking Extend syntax with types:  ::=  1   2 |  e ::= x: . e | x | e 1 e 2 (The dot  is just the base case for types, to stop the recursion. Values of this type will never be invoked, just passed around.)

34 Typing judgments Introduce a compact notation for defining typechecking rules A typing judgment:  ├ e :  "In the typing context , expression e has type  " A typing context: a mapping from variables to their types Syntax:  ::= {} | , x : 

35 Typing rules Give typechecking rule(s) for each kind of expression Write as a logical inference rule premise 1 … premise n (n  0) ––––––––––––––––– conclusion Whenever all the premises are true, can deduce that the conclusion is true If no premises, then called an "axiom" Each premise and conclusion has the form of a typing judgment

36 Typing rules for simply-typed -calculus , x:  1 ├ e :  2 ––––––––––––––––––– [T-ABS]  ├ ( x:  1. e) :  1   2 ––––––––––– [T-VAR]  ├ x :  (x)  ├ e 1 :  2    ├ e 2 :  2 ––––––––––––––––––––––––– [T-APP]  ├ (e 1 e 2 ) : 

37 Examples

38 Typing derivations To prove that a term has a type in some typing context, chain together a tree of instances of the typing rules, leading back to axioms If can't make a derivation, then something isn't true

39 Examples

40 Formalizing variable lookup What does  (x) mean? What if  includes several different types for x?  = x: , y: , x:   , x: , y:      Can this happen? If it can, what should it mean? Any of the types is OK? Just the leftmost? rightmost? None are OK?

41 An example What context is built in the typing derivation for this expression? x:  1. ( x:  2. x) What should the type of x in the body be? How should  (x) be defined?

42 Formalizing using judgments ––––––––––––– [T-VAR-1] , x:  ├ x :   ├ x :  x  y ––––––––––––––– [T-VAR-2] , y:  2 ├ x :  What about the  = {} case?

43 Type-checking self-application What type should I give to x in this term? x:?. (x x) What type should I give to the f and x's in Y? Y  f:?. ( x:?. f (x x)) ( x:?. f (x x))

44 Amazing fact #N+1: All simply- typed -calculus exprs terminate! Cannot express looping or recursion in simply-typed -calculus Requires self-application, which requires recursive types, which simply-typed -calculus doesn't have So all programs are guaranteed to never loop or recur, and terminate in a finite number of reduction steps! (Simply-typed -calculus could be a good basis for programs that must be guaranteed to finish, e.g. typecheckers, OS packet filters, …)

45 Adding an explicit recursion operator Several choices; here's one: add an expression "fix e" Define its reduction rule: fix e   e (fix e) Define its typing rule:  ├ e :    –––––––––––––– [T-FIX]  ├ (fix e) : 

46 Defining reduction precisely Use inference rules to define   redexes precisely ––––––––––––––––––– [E-ABS] ––––––––––––– [E-FIX] ( x: . e 1 ) e 2   [x  e 2 ]e 1 fix e   e (fix e) e 1   e 1 ' e 2   e 2 ' ––––––––––––– [E-APP1] ––––––––––––– [E-APP2] e 1 e 2   e 1 ' e 2 e 1 e 2   e 1 e 2 ' e 1   e 1 ' ––––––––––––––––– [E-BODY] optional x: . e 1   x: . e 1 '

47 Formalizing evaluation order Can specify evaluation order by identifying which computations have been fully evaluated (have no redexes left), i.e., values v one option: v ::= x: . e another option: v ::= x: . v what's the difference?

48 Example: call-by-value rules v ::= x: . e ––––––––––––––––––– [E-ABS] –––––––––––– [E-FIX] ( x: . e 1 ) v 2   [x  v 2 ]e 1 fix v   v (fix v) e 1   e 1 ' e 2   e 2 ' ––––––––––––– [E-APP1] ––––––––––––– [E-APP2] e 1 e 2   e 1 ' e 2 v 1 e 2   v 1 e 2 '

49 Type soundness What's the point of a static type system? Identify inconsistencies in programs Early reporting of possible bugs Document (one aspect of) interfaces precisely Provide info for more efficient compilation Most assume that type system "agrees with" evaluation semantics, i.e., is sound Two parts to type soundness: preservation and progress

50 Preservation Type preservation: if an expression has a type, and that expression reduces to another expression/value, then that other expression/value has the same type If  ├ e :  and e   e', then  ├ e' :  Implies that types correctly "abstract" evaluation, i.e., describe what evaluation will produce

51 Progress If an expression successfully typechecks, then either the expression is a value, or evaluation can take a step If  ├ e : , then e is a v or  e' s.t. e   e' Implies that static typechecking guarantees successful evaluation without getting stuck "well-typed programs don't go wrong"

52 Soundness Soundness = preservation + progress If  ├ e : , then e is a v or  e' s.t. e   e' and  ├ e' :  preservation sets up progress, progress sets up preservation Soundness ensures a very strong match between evaluation and typechecking

53 Other ways to formalize semantics We've seen evaluation formalized using small-step (structural) operational semantics An alternative: big step (natural) operational semantics Judgments of the form e  v "Expression e evaluates fully to value v"

54 Big-step call-by-value rules ––––––––––––––––– [E-ABS] ( x: . e)  ( x: . e) e 1  ( x: . e) e 2  v 2 ([x  v 2 ]e)  v ––––––––––––––––––––––––––––––––– [E-APP] (e 1 e 2 )  v e 1  ( x: . e) ([x  (fix ( x: . e))]e)  v –––––––––––––––––––––––––––––––––––– [E-FIX] (fix e 1 )  v Simpler, fewer tedious rules than small-step; "natural" Cannot easily prove soundness for non-terminating programs Typing judgments are "big step"; why?

55 Yet another variation Real machines and interpreters don't do substitution of values for variables when calling functions Expensive! Instead, they maintain environments mapping variables to their values A.k.a. stack frames We can formalize this For big step, judgments of the form  ├ e  v where  is a list of x=v bindings "In environment , expr. e evaluates fully to value v"

56 Explicit environment rules –––––––––––––––––––– [E-ABS]  ├ ( x: . e)  ( x: . e)  ├ e 1  ( x: . e)  ├ e 2  v 2 ,x=v 2 ├ e  v ––––––––––––––––––––––––––––––––––––––––– [E-APP]  ├ (e 1 e 2 )  v  ├ e 1  ( x: . e) ,x=(fix ( x: . e)) ├ e  v ––––––––––––––––––––––––––––––––––––––––– [E-FIX]  ├ (fix e 1 )  v Problems handling fix, since need to delay evaluation of recursive call Wrong! specifies dynamic scoping!

57 Explicit environments with closure values v ::= –––––––––––––––––––––––––– [E-ABS]  ├ ( x: . e)   ├ e 1   ├ e 2  v 2  ',x=v 2 ├ e  v ––––––––––––––––––––––––––––––––––––––––––––––– [E-APP]  ├ (e 1 e 2 )  v Does static scoping, as desired Allows formal reasoning about explicit environments We found a bug in implementation of substitution via environments Makes proofs much more complicated

58 Other semantic frameworks We've seen several examples of operational semantics Like specifying an interpreter, or a virtual machine An alternative: denotational semantics Specifies the meaning of a term via translation into another (well-specified) language, usually mathematical functions Like specifying a compiler! More "abstract" than operational semantics Another alternative: axiomatic semantics Specifies the result of expressions and effect of statements on properties known before and after Suitable for formal verification proofs

59 Richer languages To gain experience formalizing language constructs, consider: ints, bools let records tagged unions recursive types, e.g. lists mutable refs

60 Basic types Enrich syntax:  ::= … | int | bool e ::= … | 0 | … | true | false | e 1 + e 2 | … | if e 1 then e 2 else e 3 v ::= … | 0 | … | true | false

61 Add evaluation rules E.g., using big-step operational semantics ––––– [E-VAL] (generalizes E-ABS) v  v e 1  v 1 e 2  v 2 v 1,v 2 in Int v = v 1 +v 2 ––––––––––––––––––––––––––––––––––– [E-PLUS] (e 1 + e 2 )  v e 1  true e 2  v 2 ––––––––––––––––––––– [E-IF-true] (if e 1 then e 2 else e 3 )  v 2 e 1  false e 3  v 3 ––––––––––––––––––––– [E-IF-false] (if e 1 then e 2 else e 3 )  v 3 If no old rules need to be changed, then orthogonal + and if might not always reduce; evaluation can get stuck

62 Add typing rules ––––––––– [T-INT]  ├ 0 : int ––––––––––––– [T-TRUE]  ├ true : bool  ├ e 1 : int  ├ e 2 : int ––––––––––––––––––––––– [T-PLUS]  ├ (e 1 + e 2 ) : int  ├ e 1 : bool  ├ e 2 :   ├ e 3 :  ––––––––––––––––––––––––––––––––––– [T-IF]  ├ (if e 1 then e 2 then e 3 ) :  Type soundness: if e typechecks, then can't get stuck

63 Let e ::= … | let x=e 1 in e 2 e 1  v 1 ([x  v 1 ]e 2 )  v 2 ––––––––––––––––––––––– [E-LET] (let x=e 1 in e 2 )  v 2  ├ e 1 :  1 , x:  1 ├ e :  2 ––––––––––––––––––––––––– [T-LET]  ├ (let x=e 1 in e 2 ) :  2

64 Records Syntax:  ::= … | {n 1 :  1, …, n n :  n } e ::= … | {n 1 =e 1, …, n n =e n } | #n e v ::= … | {n 1 =v 1, …, n n =v n }

65 Evaluation and typing e 1  v 1 … e n  v n –––––––––––––––––––––––––––––––– [E-RECORD] {n 1 =e 1, …, n n =e n }  {n 1 =v 1, …, n n =v n } e  {n 1 =v 1, …, n n =v n } –––––––––––––––––– [E-PROJ] (#n i e)  v i  ├ e 1 :  1 …  ├ e n :  n –––––––––––––––––––––––––––––––––– [T-RECORD]  ├ {n 1 =e 1, …, n n =e n } : {n 1 :  1, …, n n :  n }  ├ e : {n 1 :  1, …, n n :  n } –––––––––––––––––––– [T-PROJ]  ├ (#n i e) :  i

66 Tagged unions A union of several cases, each of which has a tag Type-safe: cannot misinterpret value under tag  ::= … | e ::= … | | case e of => e 1 … => e n v ::= … | Example: val u: = if … then else case u of => j+4 => if t then 8 else 9

67 Evaluation and typing e  v –––––––––––––– [E-UNION]  e  ([x i  v i ]e i )  v ––––––––––––––––––––––––––––––––––––––– [E-CASE] (case e of =>e 1 … =>e n )  v  ├ e i :  i –––––––––––––––––––––––––– [T-UNION]  ├ :  ├ e : ,x 1 :  1 ├ e 1 :  … ,x n :  n ├ e n :  –––––––––––––––––––––––––––––––––––––––––– [T-CASE]  ├ (case e of =>e 1 … =>e n ) :  Where get the full type of the union in T-UNION?

68 Lists Use tagged unions to define lists: int_list  But int_list is defined recursively As with recursive function definitions, need to carefully define what this means

69 Recursive types Introduce a recursive type:  X.   can refer to X to mean the whole type, recursively int_list   L. This type means the infinite tree of "unfoldings" of the recursive reference If  contains a union type with non-recursive cases (base cases for the recursively defined type), then can have finite values of this "infinite" type }> }>}> …

70 Folding and unfolding What values have recursive types? What can we do with a value of recursive type? Can take a value of the body of the recursive type, and "fold" it up to make a recursive type int_list   L. : fold : int_list Can "unfold" it to do the reverse Exposes the underlying type, so operations on it typecheck Can introduce fold & unfold expressions, or can make when to do folding & unfolding implicit

71 Typing of fold and unfold  ├ e : [X  (  X.  )]  ––––––––––––––––– [T-FOLD]  ├ (fold e):  X.   ├ e :  X.  –––––––––––––––––––––––– [T-UNFOLD]  ├ (unfold e) : [X  (  X.  )]  Evaluation ignores fold & unfold

72 Using recursive values and types double: double all elems of an int_list int_list   L. double  fix ( double:(int_list  int_list). lst:int_list. case (unfold lst) of => fold => fold )

73 References and mutable state Syntax:  ::= … |  ref e ::= … | ref e | ! e | e 1 := e 2 v ::= … | ref v Typing:  ├ e :  ––––––––––––––– [T-REF]  ├ (ref e) :  ref  ├ e :  ref ––––––––––– [T-DEREF]  ├ (! e) :   ├ e 1 :  ref  ├ e 2 :  –––––––––––––––––––––– [T-ASSIGN]  ├ (e 1 := e 2 ) : unit

74 Evaluation of references e  v ––––––––––––– [E-REF] (ref e)  (ref v) e  (ref v) ––––––––– [E-DEREF] (! e)  v e 1  (ref v 1 ) e 2  v 2 –––––––––––––––––– [E-ASSIGN] (e 1 := e 2 )  unit But where'd the assignment go?

75 Example (let r = ref 0 in (let x = (r := 2) in (! r)))

76 Stores Introduce a store  to keep track of the contents of references A map from locations to values "ref e" allocates a new location and initializes it with (the result of evaluating) e "! e" looks up the contents of the location (resulting from evaluating) e in the store "e 1 := e 2 " updates the location (resulting from evaluating) e 1 to hold (the result of evaluating) e 2, returning the updated store Evaluation now passes along the current store in which to evaluate expressions Big-step judgments of the form 

77 Big-step semantics with stores ––––––––––––– [E-VAL]  –––––––––––––––––––––– [E-APP] 

78 Semantics of references Add locations l as a new kind of value (not "ref v") v ::= … | l New semantics  l  dom(  ')  '' =  '[ l  v] –––––––––––––––––––––––––––––––––––––– [E-REF]   v =  '( l ) –––––––––––––––––––––– [E-DEREF]     ''' =  ''[ l  v 2 ] ––––––––––––––––––––––––––––––––––––––––––– [E-ASSIGN] 

79 Example again (let r = ref 0 in (let x = (r := 2) in (! r)))

80 Summary, so far Now have also seen simply typed -calculus Saw inference rules, derivations Saw several ways to formalize operational semantics and typing rules Saw many extensions to this core language Typical of how real PL theorists work Usually orthogonal to underlying semantics References required redoing underlying semantics Would you want to use this language? If it had suitable syntactic sugar?

81 Polymorphic types Simply typed -calculus is "simply typed", i.e., it has no polymorphic or parameterized types "Good" programming languages have polymorphic types And there are tricky issues relating to polymorphic types So we'd like to capture the essense of polymorphic types in our calculus So we'll really understand it

82 Polymorphic -calculus Also known as System F Extend type syntax with a forall type  ::= … |  X.  | X Now can write down the types of polymorphic values id   T. T  T map   'a.  'b. ('a  'b)  'a list  'b list nil   T. T list

83 Values of polymorphic type Introduce explicit notation for values of polymorphic type and their instantiations A polymorphic value:  X. e  X. e is a function that, given a type , gives back e with  substituted for X Use such values by instantiating them: e[  ] e[  ] is like function application Syntax: e ::= … |  X. e | e[  ] v ::= … |  X. e

84 An example (* fun id x = x; id : 'a->'a *) id   'a. x:'a. x :  'a. 'a  'a id [int] 3   ( x:int. x) 3   3 id [bool]   x:bool. x

85 Another example (* fun doTwice f x = f (f x); doTwice: ('a->'a)->'a->'a *) doTwice   'a. f:'a  'a. x:'a. f (f x) :  'a. ('a  'a)  'a  'a doTwice [int] succ 3   ( f:int  int. x:int. f (f x)) succ 3   * succ (succ 3)   * 3

86 Yet another example map   'a.  'b. fix ( map:('a  'b)  'a list  'b list. f:'a  'b. lst:'a list. fold (case (unfold lst) of => => )) :  'a.  'b. ('a  'b)  'a list  'b list map [int] [bool] isZero [3,0,5]   * [false,true,false] ML infers what the  T and [  ] should be

87 A final example (* fun cool f = (f 3, f true) *) cool  f:(  'a. 'a  'a). (f [int] 3, f [bool] true) : (  'a. 'a  'a)  (int * bool) cool id   (id [int] 3, id [bool] true)   * (( x:int. x) 3, ( x:bool. x) true)   * (3, true) Note:  inside of and  Can't write this in ML; not "prenex" form

88 Evaluation and typing rules Evaluation: e  (  X. e 1 ) ([X  ]e 1 )  v –––––––––––––––––––––––– [E-INST] (e[  ])  v Typing: , X::type ├ e :  ––––––––––––––––– [T-POLY]  ├ (  X. e) :  X.   ├ e :  X.  ' ––––––––––––––––– [T-INST]  ├ (e[  ]) : [X  ]  '

89 Different kinds of functions x. e is a function from values to values  X. e is a function from types to values What about functions from types to types? Type constructors like , list, BTree We want them! What about functions from values to types? Dependent types like the type of arrays of length n, where n is a run-time computed value Pretty fancy, but would be very cool

90 Type constructors What's the "type" of list? Not a simple type, but a function from types to types e.g. list(int) = int_list There are lots of type constructors that take a single type and return a type They all have the same "meta-type" Other things take two types and return a type (e.g. , assoc_list) A "meta-type" is called a kind

91 Kinds A type describes a set of values or value constructors (a.k.a. functions) with a common structure  ::= int |  1   2 | … A kind describes a set of types or type constructors with a common structure  ::= type |  1   2 Write  ::  to say that a type  has kind  int :: type int  int :: type list :: type  type list int :: type assoc_list :: type  type  type assoc_list string int :: type

92 Kinded polymorphic -calculus Also called System F  Full syntax:  ::= type |  1   2  ::= int |  1   2 |  X:: .  | X | X:: .  |  1  2 e ::= x: . e | x | e 1 e 2 |  X:: . e | e[  ] v ::= x. e |  X:: . e Functions and applications at both the value and the type level Arrows at both the type and kind level

93 Examples pair  'a::type. 'b::type. {first:'a, second:'b} :: type  type  type pair int bool "   " {first:int, second:bool} {first=5, second=true} : pair int bool swap   'a::type.  'b::type. p:pair 'a 'b. {first=#second p, second=#first p} :  'a::type.  'b::type. (pair 'a 'b)  (pair 'b 'a)

94 Expression typing rules  ├  1 ::type , x:  1 ├ e :  2 –––––––––––––––––––––––– [T-ABS]  ├ ( x:  1. e) :  1   2 , X::  ├ e :  ––––––––––––––––––––– [T-POLY]  ├ (  X:: . e) :  X:: .   ├ e :  X:: .  '  ├  ::  ––––––––––––––––––––––– [T-INST]  ├ (e[  ]) : [X  ]  ' (T-VAR and T-APP unchanged)

95 Type kinding rules  ├  1 :: type  ├  2 :: type –––––––––––– [K-INT] ––––––––––––––––––––––––– [K-ARROW]  ├ int :: type  ├ (  1   2 ) :: type , X::  ├  :: type –––––––––––––––––– [K-FORALL] ––––––––––– [K-VAR]  ├ (  X:: .  ) :: type  ├ X ::  (X) , X::  1 ├  ::  2  ├  1 ::  2    ├  2 ::  2 ––––––––––––––––––––– [K-ABS] –––––––––––––––––––––– [K-APP]  ├ ( X::  1.  ) ::  1   2  ├ (  1  2 ) :: 

96 Summary Saw ever more powerful static type systems for the -calculus Simply typed -calculus Polymorphic -calculus, a.k.a. System F Kinded poly. -calculus, a.k.a. System F  Exponential ramp-up in power, once build up sufficient critical mass Real languages typically offer some of this power, but in restricted ways Could benefit from more expressive approaches

97 Other uses Compiler internal representations for advanced languages E.g. FLINT: compiles ML, Java, … Checkers for interesting non-type properties, e.g.: proper initialization static null pointer dereference checking safe explicit memory management thread safety, data-race freedom