Dynamically Typed Programming Languages Part 1: The Untyped λ -Calculus Jim Royer CIS 352 April 16, 2019 Royer Dynamically Typed Programming Languages 1 / 22
Reference Practical Foundations for Programming Languages, 2/e, “Part VI: Dynamic Types” , by Robert Harper, Cambridge University Press, 2016, pages 183–210. https://www.cs.cmu.edu/%7Erwh/pfpl/2nded.pdf Note: Harper doesn’t much care for “dynamically typed languages” and his criticisms are dead on, but these languages do have some advantages. Lambda calculus definition , from Wikipedia. https://en.wikipedia.org/wiki/Lambda_calculus_definition Royer Dynamically Typed Programming Languages 2 / 22
Important!!! dynamically typed �≡ dynamically scoped Dynamically typed roughly means we may not find out the type of a value until runtime. Dynamically scoped roughly means we may not find out a variable’s binding until runtime. Dynamically Typed Programming Languages include: Lisp, Scheme, Racket, Python, Clojure, Erlang, JavaScript, Julia, Lua, Perl, R, Ruby, Smalltalk, . . . (See https://en.wikipedia.org/wiki/Dynamic_programming_language#Examples .) The “premier example” is the (untyped) λ -calculus. Royer Dynamically Typed Programming Languages 3 / 22
The λ -Calculus Royer Dynamically Typed Programming Languages 4 / 22
The λ -Calculus: Beginnings Alonzo Church originally developed the λ -calculus as part of a grand formalism for the foundations of mathematics. But . . . Royer Dynamically Typed Programming Languages 5 / 22
The λ -Calculus: Beginnings Alonzo Church originally developed the λ -calculus as part of a grand formalism for the foundations of mathematics. But . . . Stephen Kleene and Barkely Rosser showed that system was inconsistent. So . . . Royer Dynamically Typed Programming Languages 5 / 22
The λ -Calculus: Beginnings Alonzo Church originally developed the λ -calculus as part of a grand formalism for the foundations of mathematics. But . . . Stephen Kleene and Barkely Rosser showed that system was inconsistent. So . . . The formalism was cut back to the part that was about defining functions, λ -calculus. Amazingly . . . Royer Dynamically Typed Programming Languages 5 / 22
The λ -Calculus: Beginnings Alonzo Church originally developed the λ -calculus as part of a grand formalism for the foundations of mathematics. But . . . Stephen Kleene and Barkely Rosser showed that system was inconsistent. So . . . The formalism was cut back to the part that was about defining functions, λ -calculus. Amazingly . . . The λ -calculus turns out to be Turing-complete . Why “amazingly”? Royer Dynamically Typed Programming Languages 5 / 22
The λ -Calculus: Beginnings Alonzo Church originally developed the λ -calculus as part of a grand formalism for the foundations of mathematics. But . . . Stephen Kleene and Barkely Rosser showed that system was inconsistent. So . . . The formalism was cut back to the part that was about defining functions, λ -calculus. Amazingly . . . The λ -calculus turns out to be Turing-complete . Why “amazingly”? Because on the surface there is not very much to the λ -calculus. Royer Dynamically Typed Programming Languages 5 / 22
Definitions, 1 Concrete Syntax ∗ E :: = X (variable occurrence) | ( E E ) (function application) | λ X . E (function abstraction) X :: = identifiers ∗ Note: We sometimes add extra parens around lambda-expressions. E.g., we can write (( λ x . ( y x )) z ) for ( λ x . ( y x ) z ) . Also, by convention application associates to the left. E.g., we can write w x y z for ((( w x ) y ) z ) as in Haskell. Harper uses a LISPy concrete syntax for λ x . e . E.g.: λ ( x ) e Royer Dynamically Typed Programming Languages 6 / 22
Free and bound variables E :: = X | ( E E ) | λ X . E Abstract Syntax (in Haskell) type Name = String data Exp = Id Name | App Exp Exp | Lam Name Exp App I B F F (( λ x . ( x z )) x ) Lam x Id x App I = binding occurrence B = bound occurence F = free occurence Id x Id z Royer Dynamically Typed Programming Languages 7 / 22
Computations Definition An expression of the form: (( λ x . e 0 ) e 1 ) is called a β -redex . (( λ x . e 0 ) e 1 ) β -reduces to e 0 [ e 1 / x ] . e β -reduces to e ′ when e ′ is the result of replacing some subexpression of e of the form (( λ x . e 0 ) e 1 ) with e 0 [ e 1 / x ] . e is in β -normal form when it contains no β -redexes. Examples (( λ x . ( plus x z )) y ) → β ( plus y z ) (( λ w . ( plus w z )) ( times x y )) → β ( plus ( times x y ) z ) (( λ x . ( λ z . ( plus x z ))) y ) → β ( λ z . ( plus y z )) (( λ x . ( λ y . ( plus x y ))) y ) �→ β ( λ y . ( plus y y )) variable capture!! (( λ x . ( λ y . ( plus x y ))) y ) → β ( λ z . ( plus y z )) ( x ( λ y . y )) �→ β anything as it is in normal form Ω = def (( λ x . ( x x )) ( λ x . ( x x ))) → β (( λ x . ( x x )) ( λ x . ( x x ))) = Ω Royer Dynamically Typed Programming Languages 8 / 22
β -reduction’s less glamorous siblings α -conversion (Bound vars don’t mater for meaning) λ x . e ≡ α λ y . ( e [ y / x ]) where x � = y . (I.e., Renaming bound vars doesn’t change meaning.) η -conversion (Extensionality) (( λ x . e ) x ) ≡ η e when x / ∈ freeVars ( e ) . (I.e., λ -terms producing the same result on all args are equivalent.) Royer Dynamically Typed Programming Languages 9 / 22
Normal Order Evaluation (think preorder) The Normal Order Evaluation Strategy Always do the leftmost possible beta-reduction. Repeat until (if ever) you reach a normal form. [Draw the parse tree!] Normal Order Evaluation Strategy is equivalent to: function nor ( M ) if M = (( λ x . N ) P ) then nor ( N [ P / x ]) then nor ( ( N ′ P ) ) else if M = ( N P ) & N → n . o . N ′ else if M = ( N P ) & P → n . o . P ′ then nor ( ( N P ′ ) ) & N → n . o . N ′ then nor ( λ x . N ′ ) else if M = λ x . N ( ‡ ) else (* M is in β -n.f. *) return M Theorem If e has a normal form, normal order evaluation will eventually reach it. (‡) Drop this line to get to call-by-name . Royer Dynamically Typed Programming Languages 10 / 22
Applicative Order Evaluation (think postorder) The Applicative Order Evaluation Strategy Always do the innermost (to the left) possible beta-reduction. Repeat until (if ever) you run out of beta-redexes. [Draw the parse tree!] Normal Order Evaluation Strategy is equivalent to: function nor ( M ) then nor ( ( N ′ P ) ) M = ( N P ) & N → n . o . N ′ if else if M = ( N P ) & P → n . o . P ′ then nor ( ( N P ′ ) ) else if M = (( λ x . N ) P ) then nor ( N [ P / x ]) & N → n . o . N ′ then nor ( λ x . N ′ ) else if M = λ x . N ( ‡ ) else (* M is in β -n.f. *) return M Fact If e has a normal form, applicative order evaluation may not find it. (‡) Drop this line to get to call-by-value . Royer Dynamically Typed Programming Languages 11 / 22
Aside: Are there other evaluation strategies? More than you want to know. For starts, see: https://en.wikipedia.org/wiki/Evaluation_strategy Royer Dynamically Typed Programming Languages 12 / 22
The λ -calculus as a RISC assembly language, 1 Church Booleans Church Pairs true = def λ t . λ f . t pair = def λ f . λ s . λ b . (( b f ) s ) false = def λ t . λ f . f fst = def λ p . ( p true ) test = def λ b . λ m . λ n . (( l m ) n ) snd = def λ p . ( p false ) and = def λ b . λ c . (( b c ) false ) Examples Examples fst ( pair u v ) → ∗ β u test true u v → ∗ β u snd ( pair u v ) → ∗ β u test false u v → ∗ β v and true true → ∗ β true and false true → ∗ β false . . . Royer Dynamically Typed Programming Languages 13 / 22
The λ -calculus as a RISC assembly language, 2 Church Numerals c 0 = def λ s . λ z . z c 1 = def λ s . λ z . ( s z ) “Object oriented integers” c 2 = def λ s . λ z . ( s ( s z )) specify what successor ( s ) is c 3 = def λ s . λ z . ( s ( s ( s z ))) specify what zero ( z ) is . . . c n = apply s n -times to z successor = def λ n . λ s . λ z . ( s ( n s z )) predecessor is difficult ( pred c 0 → β c 0 & plus = def λ m . λ n . λ s . λ z . m s ( n s z ) pred c n + 1 → β c n ) times = def λ m . λ n . ( m ( plus n ) c 0 ) . . . Y = def λ f . ( λ x . f ( x x ))( λ x . f ( x x )) Royer Dynamically Typed Programming Languages 14 / 22
From Barendregt’s Impact of the Lambda calculus Kleene did find a way to lambda de- fine the predecessor function in the un- typed lambda calculus, by using an appropriate data type (pairs of inte- gers) as auxiliary device. In [69], he described how he found the solution while being anesthetized by laughing gas (N 2 O) for the removal of four wis- dom teeth. http://www-users.mat.umk.pl/~adwid/materialy/doc/church.pdf Royer Dynamically Typed Programming Languages 15 / 22
From Barendregt’s Impact of the Lambda calculus Kleene did find a way to lambda de- fine the predecessor function in the un- typed lambda calculus, by using an appropriate data type (pairs of inte- gers) as auxiliary device. In [69], he described how he found the solution while being anesthetized by laughing gas (N 2 O) for the removal of four wis- dom teeth. http://www-users.mat.umk.pl/~adwid/materialy/doc/church.pdf So yes, drugs were involved in all of this. Royer Dynamically Typed Programming Languages 15 / 22
Back to Harper Royer Dynamically Typed Programming Languages 16 / 22
Recommend
More recommend