why formalize
play

Why formalize? n ML is tricky, particularly in corner cases Formal - PDF document

Why formalize? n ML is tricky, particularly in corner cases Formal Semantics n generalizable type variables? n polymorphic references? n exceptions? n Some things are often overlooked for any language n evaluation order? side-effects? errors? n


  1. Why formalize? n ML is tricky, particularly in corner cases Formal Semantics n generalizable type variables? n polymorphic references? n exceptions? n Some things are often overlooked for any language n evaluation order? side-effects? errors? n Therefore, want to formalize what a language's definition really is n Ideally, a clear & unambiguous way to define a language n Programmers & compiler writers can agree on what's supposed to happen, for all programs n Can try to prove rigorously that the language designer got all the corner cases right 1 2 Aspects to formalize Approach n Syntax : what's a syntactically well-formed program? n Formalizing full-sized languages is very hard, n EBNF notation for a context-free grammar tedious n Static semantics : which syntactically well-formed n many cases to consider programs are semantically well-formed? which n lots of interacting features programs type-check? n Better: boil full-sized language down into n typing rules, well-formedness judgments essential core , then formalize and study the n Dynamic semantics : what does a program core evaluate to or do when it runs? n operational, denotational, or axiomatic semantics n cut out as much complication as possible, without n Metatheory : properties of the formalization itself losing the key parts that need formal study n E.g. do the static and dynamic semantics match? i.e., n hope that insights gained about core will carry is the static semantics sound w.r.t. the dynamic semantics? back to full-sized language 3 4 The lambda calculus Untyped l -calculus: syntax n The essential core of a (functional) n (Abstract) syntax: programming language e ::= x variable n Developed by Alonzo Church in the 1930's | l x . e function/abstraction n Before computers were invented! ( @ fn x => e ) n Outline: | e 1 e 2 call/application n Untyped: syntax, dynamic semantics, cool n Freely parenthesize in concrete syntax to imply properties the right abstract syntax n Simply typed: static semantics, soundness, more n The trees described by this grammar are cool properties called term trees n Polymorphic: fancier static semantics 5 6 1

  2. a -renaming Free and bound variables n l x . e binds x in e n First semantic property of lambda calculus: bound variables in a term tree can be n An occurrence of a variable x is free in renamed (properly) without affecting the e if it's not bound by some enclosing semantics of the term tree lambda a -equivalent term trees n a a a freeVars( x ) ” x n ( l x 1 . x 2 x 1 ) a ( l x 3 . x 2 x 3 ) freeVars( l x . e ) ” freeVars( e ) – { x } n cannot rename free variables freeVars( e 1 e 2 ) ” freeVars( e 1 ) ¨ freeVars( e 2 ) n term e : e and all a -equivalent term trees n e is closed iff freeVars( e ) = {} n Can freely rename bound vars whenever helpful 7 8 Evaluation: b -reduction Examples n Define what it means to "run" a lambda-calculus program by giving simple reduction/rewriting/simplification rules n " e 1 fi b e 2 " means " e 1 evaluates to e 2 in one step" n One case: n ( l x . e 1 ) e 2 fi b [ x fi e 2 ] e 1 n "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" n Can do this rewrite anywhere inside an expression 9 10 Substitution Result of reduction n To fully evaluate a lambda calculus n When doing substitution, must avoid term, simply perform b -reduction until changing the meaning of a variable occurrence you can't any more [ x fi e ] x ” e n fi b * ” reflexive, transitive closure of fi b [ x fi e ] y ” y if x „ y n When you can't any more, you have a [ x fi e ]( l x . e 2 ) ” ( l x . e 2 ) value , which is a normal form of the [ x fi e ]( l y . e 2 ) ” ( l y . [ x fi e ] e 2 ) if x „ y input term and y not free in e [ x fi e ]( e 1 e 2 ) ” ([ x fi e ] e 1 ) ([ x fi e ] e 2 ) n Does every lambda-calculus term have a n can use a -renaming to ensure " y not free in e " normal form? 11 12 2

  3. Reduction order Two reduction orders n Can have several lambdas applied to an n Normal-order reduction argument in one expression (a.k.a. call-by-name, lazy evaluation) n Each called a redex n reduce leftmost, outermost redex n Therefore, several possible choices in n Applicative-order reduction reduction (a.k.a. call-by-value, eager evaluation) n Which to choose? Must we do them all? n reduce leftmost, outermost redex n Does it matter? whose argument is in normal form n To the final result? (i.e., is a value) n To how long it takes to compute? n To whether the result is computed at all? 13 14 Amazing fact #1: Existence of normal forms? Church-Rosser Theorem, Part 1 n Thm. If e 1 fi b * e 2 and e 1 fi b * e 3 , then n Does every term have a normal form? $ e 4 such that e 2 fi b * e 4 and e 3 fi b * e 4 e 1 n Consider: ( l x . x x ) ( l y . y y ) e 3 e 2 e 4 n Corollary. Every term has a unique normal form, if it has one n No matter what reduction order is used! 15 16 Amazing fact #2: Weak head normal form Church-Rosser Theorem, Part 2 n What should this evaluate to? n If a term has a normal form, then ( l y . ( l x . x x ) ( l x . x x )) normal-order reduction will find it! n Normal-order and applicative-order evaluation run forever n Applicative-order reduction might not! n But in regular languages, wouldn't evaluate the function's body until we called it n "Head" normal form doesn't evaluate arguments until function expression is a lambda n Example: n "Weak" evaluation doesn't evaluate under lambda n ( l x 1 . ( l x 2 . x 2 )) (( l x . x x ) ( l x . x x )) n With these alternative definitions of reduction: n Reduction terminates on more lambda terms n Correspond more closely to real languages (particularly "weak") 17 18 3

  4. Amazing fact #3: Multiple arguments: currying l -calculus is Turing-complete! n But the l -calculus is too weak, right? n Encode multiple arguments via curried n No multiple arguments! functions, just as in regular ML n No numbers or arithmetic! n No booleans or if! l ( x 1 , x 2 ). e ⇒ l x 1 . ( l x 2 . e ) ( ” l x 1 x 2 . e ) n No data structures! f ( e 1 , e 2 ) ⇒ ( f e 1 ) e 2 n No loops or recursion! 19 20 Church numerals Arithmetic on Church numerals n Successor function: n Encode natural numbers using stylized take (the encoding of) a number, lambda terms return (the encoding of) its successor zero ” l s . l z . z n I.e., add an s to the argument's encoding succ ” l n . l s . l z . s ( n s z ) one ” l s . l z . s z two ” l s . l z . s ( s z ) succ zero fi b l s . l z . s ( zero s z ) fi b * … l s . l z . s z = one n ” l s . l z . s n z succ two fi b n A unary encoding using functions l s . l z . s ( two s z ) fi b * n No stranger than binary encoding l s . l z . s ( s ( s z )) = three 21 22 Addition Booleans n Key idea: true and false are encoded n To add x and y , apply succ to y x times as functions that do different things to n Key idea: x is a function that, given a function and a base, applies the function to the base x times their arguments, i.e., make a choice n "a number is as a number does" if ” l b . l t . l e . b t e plus ” l x . l y . x succ y true ” l t . l e . t false ” l t . l e . e plus two three fi b * two succ three fi b * if false four six fi b * succ ( succ three ) = five false four six fi b * n Multiplication is repeated addition, similarly six 23 24 4

Recommend


More recommend