200 likes | 232 Views
Understand applicative order vs. normal order evaluation in programming languages with type checking, inference, and verification concepts. Learn how to define functions using let, check the correctness of types, perform type inference, and apply typing axioms and rules. Explore type assignments, typing statements, and construct static type inference systems.
E N D
PPL Applicative and Normal Form Verification, Type Checking and Inference
Applicative order vs. Normal OrderEvaluation To Evaluate a combination: (other than special form) Evaluate all of the sub-expressions in any order Applythe procedure that is the value of the leftmost sub-expression to the arguments (the values of the other sub-expressions)
Applicative order evaluation rules Combination... (<operator> <operand1> …… <operand n>) • Evaluate <operator> to get the procedure and evaluate <operands> to get the arguments • If <operator> is primitive: do whatever magic it does • If <operator> is compound: evaluate body with formal parameters replaced by arguments
Normal order evaluation Combination … (<operator> <operand1> …… <operand n>) • Evaluate <operator> to get the procedure and evaluate <operands> to get the arguments • If <operator> is primitive: do whatever magic it does • If <operator> is compound: evaluate body with formal parameters replaced by arguments
The Difference Normal ((lambda (x) (+ x x)) (* 3 4)) (+ (* 3 4) (* 3 4)) (+ 12 12) 24 Applicative ((lambda (x) (+ x x)) (* 3 4)) (+ 12 12) 24 This may matter in some cases: ((lambda (x y) (+ x 2)) 3 (/ 1 0)) Scheme is an Applicative Order Language!
Using let to define functions • Can we use let to define functions? • What about recursive functions?
Type Checking and Inference • Based on S. Krishnamurthi. Programming Languages: Application and Interpretation 2007. Chapters 24-26
Verification • Type correctness • Verify that the types of expressions in the program are “correct” • E.g. + is applied to numbers • In other languages: we should also check that the type of value stored in a variable correspond to the variable declared type • Program Verification • Verify that the program halts and produces the “correct” output • Somewhat easier with design-by-contract, where it can be done in a modular fashion
Languages and Types • Fully typed • C, Pascal, Java.. • Semi-typed • Scheme • Untyped • Prolog • Well-typing rules • Define relationships between types
Type Checking and Inference Type Checking. Given an expression, and a “goal” type T, verify that the expression type is T Example: Given the expression (+ (f 3) 7), we need to verify that (f 3) is a number Type Inference. Infer the type of an expression Example: (define x (f 3))
Types in Scheme • Numbers, booleans, symbols… • Union: • No value constructor • Type Constrcutor is union • Simplification rules • S union S = S • S union T = T union S • Unit Type • “Void”
Procedures and Type Polymorphism • What is the type of: • (lambda (x) x) • (lambda (f x) (f x)) • (lambda (f x) ( (f x) x)) • Instantiations, type variables renaming... • Next we construct a static type inference system
Type assignment and Typing statement • Type assignment • Mapping variables to types • Example: TA= {x<-Number, y<-[Number –> T]} • Notation: TA(x) = Number • Typing statement • TA |- e:T • Under TA, the expression e has the type T • {x<-Number} |- (+ x 5):Number • Type variables (as well as unbound variables)used in such statements are defined to be universally quantified • {x<-[T1 –> T2]} |- (x y):T2
Type assignment extension {x<-Number, y<-[Number –> T]}°{z<-Boolean} = {x<-Number, y<-[Number –> T], z<-Boolean} EMPTY° {x1<-T1, ..., xn<- Tn} = {x1<-T1, ..., xn<- Tn} Extension pre-condition: new variables are different from old ones.
Restricted Scheme (syntax) <scheme-exp> -> <exp> <exp> -> <atomic> | <composite> <atomic> -> <number> | <boolean> | <variable> <composite> -> <special> | <form> <number> -> Numbers <boolean> -> ’#t’ | ’#f’ <variable> -> Restricted sequences of letters, digits, punctuation marks <special> -> <lambda> | <quote>
<form> -> ’(’ <exp>+ ’)’ <lambda> -> ’(’ ’lambda’ ’(’ <variable>* ’)’ <exp>+ ’)’ <quote> -> ’(’ ’quote’ <variable> ’)’
Typing axioms • Typing axiom Boolean : For every type assignment TA and boolean b: TA |- b:Boolean Typing axiom Variable : For every type assignment TA and variable v: TA |- v:TA(v) Typing axioms Primitive procedure : TA |- +:[Number* ... *Number -> Number] TA |- not:[S -> Boolean] where S is a type variable. For every type assignment TA: TA |- display:[S -> Unit] S is a type variable. That is, display is a polymorphic primitive procedure.
Cont. • Typing rule Procedure : If TA{x1<-S1, ..., xn<-Sn} |- bi:Ui for all i=1..m, Then TA |- (lambda (x1 ... xn) b1 ... bm):[S1*...*Sn -> Um] Parameter-less Procedure: If TA |- bi:Ui for all i=1..m, Then TA |- (lambda ( ) b1 ... bm):[Unit -> Um] Typing rule Application : If TA |- f:[S1*...*Sn -> S], TA |- e1:S1, ..., TA |- en:Sn Then TA |- (f e1 ... en):S
Expression Trees The nesting of expressions can be viewed as a tree Sub-trees correspond to composite expressions Leaves correspond to atomic ones.
Type Inference Algorithm Algorithm Type-derivation: Input: A language expression e Output: A type expression t or FAIL Method: 1. For every leaf sub-expression of e, apart from procedure parameters, derive a typing statement by instantiating a typing axiom. Number the derived typing statements. 2. For every sub-expression e’ of e (including e): Apply a typing rule whose support typing statements are already derived, and it derives a typing statement for e’. Number the newly derived typing statement. 3. If there is a derived typing statement for e of the form e:t, Output = t. Otherwise, Output = FAIL