2IA05 Functioneel Programmeren λ-calculus en lazy evaluation Rik van Geldrop, Jaap van der Woude met dank aan Andres Löh, UU Lambda calculus,Church, 1932 2/34 • Formele taal die even krachtig is als een Turing machine. • Wiskundige basis voor functionele talen en hun implementaties. • Gebaseerd op consistente substitutie van variabelen in naamloze functies. • Evaluatie m.b.v. 3 herschrijfregels: α-, β - en η -conversie. • Veel semantische eigenschappen die afgeleid kunnen worden voor de λcalculus gelden ook voor functionele talen. Literatuur: • L.C.Paulson. Foundations of Functional Programming. • S.Thompson. Type Theory & Functional Programming. Chapter 2. • R.Plasmeijer & M.v.Eekelen. Functional Programming and Parallel Graph Rewriting. Chapter 3. • H.P.Barendregt. The Lambda Calculus, its Syntax and Semantics. / department of mathematics and computer science Lambda calculus, korte samenvatting 3/34 De λ-calculus is een herschrijfsysteem met bijbehorende theorie over eigenschappen van dat systeem. De lambda calculus houdt zich bezig met lambda-termen of lambdaexpressies, i.e. symboolrijen van de volgende vorm Definition 1 [Λ, ongetypeerde λ-terms] Zij V een oneindige verzameling van variabelen. De verzameling Λ van λ-termen is de kleinste verzameling X zodanig dat (1) (2) (3) x∈V M ∈X ∧x∈V M, N ∈ X ⇒ ⇒ ⇒ x∈X λx.M ∈ X (M N ) ∈ X variabele abstractie applicatie De λ-termen vormen dus een inductief type Λ / (ιOλO@) department of mathematics and computer science V + V ×Λ + Λ×Λ Boom-representatie van een λ-term 4/34 Variabelen in bladeren, overige constructies in knopen. x (λz.y x) λf.λx.f (f x) @ λf x λz λx @ @ y x f @ f / department of mathematics and computer science x Lambda calculus, enige toelichting: 5/34 • De term λx.M representeert de functie die, toegepast op een actueel argument, de formele parameter x instantieert met dat argument en dan de resulterende waarde van M berekent, d.i. M waarin elk voorkomen van x vervangen is door het argument. • De term (M N ) modelleert functie-applicatie: functie M wordt aangeroepen met N als argument en het resultaat wordt berekend. • We schrijven M ≡ N voor (syntactisch) identieke termen. Gelijkheid van termen, M = N , komt later aan de orde. / department of mathematics and computer science Notationele afspraken • Applicatie bindt sterker dan abstractie, dus λ x.x y betekent λ x.(x y) en niet (λ x.x) y • Applicatie associeert naar links, dus x y z betekent (x y) z en niet x (y z) • Abstractie associeert naar rechts, dus λ x1.λ x2.....λ xn.e betekent λ x1.(λ x2.....(λ xn.e)) zelfs λ x1 x2.... xn.e i.p.v. λ x1.λ x2.....λ xn.e / department of mathematics and computer science 6/34 Vrij 7/34 • Alle voorkomens van variabele x in de term λ x.M heten gebonden. Een variabele is vrij als die niet gebonden wordt door een omvattende abstractie. Voorbeeld : In λz x . y x is x gebonden en y vrij. • Een variabele kan zowel gebonden als vrij voorkomen in een term. Voorbeeld: Variabele x in x (λz x . y x) • Een variabele x wordt gebonden door de syntactisch dichtsbijzijnde linker λ x, als die bestaat. • Een expressie heet gesloten als er geen vrije variabelen zijn, anders is die open. • Een gesloten term wordt ook wel combinator genoemd. / department of mathematics and computer science Substitutie 8/34 Definition 2 [M [L/y]] De substitutie van L voor alle vrije variabelen y in M wordt gegeven door: • y [L/y] ≡ L, x[L/y] ≡ x voor x 6≡ y • (λ y.M )[L/y] ≡ λ y.M (λ x.M )[L/y] ≡ λ x.(M [L/y]) voor x 6≡ y • (M N )[L/y] ≡ (M [L/y] N [L/y]) Merk op dat de substitutie [L/y] net geen fold is over de λ-termen. Om de variabele-binding onaangetast te laten eisen we safeness: • De substitutie M [L/y] is safe als de gebonden variabelen van M disjunct zijn van de vrije variabelen van L Unsafe: (λy . x) [y/x] resulteert in λy. y . Ongewenst! / department of mathematics and computer science Herschrijvingen I 9/34 Lambda expressies kunnen herschreven worden m.b.v. conversie regels. De drie belangrijkste zijn α-, β - en η -conversie • α-conversie. Dummy change, herbenoemen van gebonden variabelen: Als y niet voorkomt in M (noch vrij, noch gebonden), dan λx.M →α λy. (M [y/x]) – Door herbenoemen met “verse” variabelen kunnen unsafe substituties safe gemaakt worden. (λy.x) [y/x] →α (λz.x) [y/x] → λz.y – Termen die door α-conversie in elkaar zijn over te voeren zullen we als syntactisch identiek beschouwen. • β -conversie. Argument substitutie. Voor disjuncte vrije variabelen van N en gebonden variabelen van M : ((λx.M ) N ) →β M [N/x] / department of mathematics and computer science Herschrijvingen II 10/34 • η -conversie. Functiegelijkheid, principe van extensionaliteit. λx . M x →η M Als x niet vrij is in M . – De termen λx . M x en M drukken beide applicatie uit: (λx . M x) y →β (M x) [y/x] ≡ M y – Termen die door η -conversie in elkaar zijn over te voeren zullen we als syntactisch identiek beschouwen. • Conversieregels kunnen ook omgekeerd worden gebruikt (expansie). Uiteraard onder dezelfde condities. λy.x y M / ←α λz.x ←β (λx.x) y ←η λx.M x department of mathematics and computer science Herschrijvingen III 11/34 Twee λ-expressies zijn gelijk als ze door “herschrijfstappen in context” in elkaar zijn over te voeren. D.w.z Gelijkheid op λ-expressies is de congruentierelatie mbt algebra (ιOλO@) voortgebracht door (→ ∪ ←)∗ . • • equivalentierelatie: reflexief, transitief, symmetrisch constructies behouden gelijkheid, i.e. als M = M 0 en N = N 0 dan ook – λx.M = λx.M 0 – (M N ) = (M 0 N 0) De α-stappen (renaming dummies) en de η -stappen (extensionaliteit) zullen we iha niet expliciet aangeven. Voor de β -stappen zullen we ons buigen over de verschillende volgordes. / department of mathematics and computer science Redexen 12/34 Intuïtief betekent gelijkheid: dezelfde waarde, hetzelfde resultaat. • Een (β -)redex (reduceerbare expressie) is een term van de vorm (λx . M ) N . • M reduceert naar N : M →∗ N Voorbeeld: (λc . c (λa b . a)) (λf . f p q) reduceert naar p • Een term kan 0 of meerdere redexen hebben Voorbeeld: (λx.x)(λy.y) ((λz.z)t) • Een term zonder redexen is in normal form. Voorbeelden: λx.x, x • Een term heeft een normal form als die tot normal form te reduceren is. Voorbeeld: (λx.x) y is niet in normal form, maar heeft normal form y • Niet elke term heeft een normal form Voorbeeld: (λx.x x) (λx.x x) → (λx.x x) (λx.x x) / department of mathematics and computer science Redexen 13/34 • Confluentie, Diamant eigenschap, Church-Rosser: Voor alle termen M , M1 , M2 met M →∗ M1 en M →∗ M2 , bestaat er een L zodanig dat M1 →∗ L en M2 →∗ L. • Gevolg: een normaalvorm van een term is uniek. • Voor een expressie met meerdere redexen kunnen verschillende reductievolgorden gekozen worden. Een reductie-strategie is een afspraak over welke redex als eerste herschreven gaat worden. • Volgens Church-Rosser leveren verschillende reductie-strategieën geen andere normal form, WEL kunnen de uitkomsten compleet verschillend zijn (bij niet normaliserende reductie). Voorbeeld: Zij Ω = (λx.x x) (λx.x x), dan / 1. (λy.a)Ω → a [Ω/y] = a 2. (λy.a)Ω → (λy.a)Ω → ..... department of mathematics and computer science Reductie-strategieen 14/34 • (λy.a)Ω → a [Ω/y] = a: normal order-strategie substitueer het argument in de abstractie, zonder dit vooraf te reduceren (call-by-name evaluatie). (λy.a)Ω → (λy.a)Ω → .....: applicatieve order-strategie (ook eager, strict). Reduceer eerst het argument en substitueer daarna in de abstractie (call-by-value evaluatie). • Normal order strategie levert een normaalvorm, als die bestaat. • De normal order strategie heet ook wel left-most outermost reductie, omdat de leftmost-outermost redex gekozen wordt voor herschrijven. outermost: niet door een andere redex omvat leftmost: links van alle andere outermost redexen. • De applicatieve order strategie ofwel left-most innermost reductie, omdat de leftmost-innermost redex gekozen wordt voor herschrijven. innermost: bevat geen andere redex / department of mathematics and computer science Reductie-strategieen 15/34 • Normal order reductie kan erg inefficient zijn omdat argumenten mogelijk meerdere malen berekend moeten worden. Voorbeeld: Zij sqr = λn.mult n n, dan sqr (sqr N ) → mult (sqr N ) (sqr N ) → mult (mult N N ) (mult N N ) De term N wordt 4× geëvalueerd; bij applicative order slechts 1× . • Door een slimme representatie van λ-termen (graaf i.p.v. boom) kan de normal-order strategie verfijnd worden tot de lazy evaluation-strategie. • Lazy evaluation (call-by-need) evalueert een argument – (Nodig) alleen als het nodig is voor de productie van het antwoord – (Deels) slechts dat deel dat nodig is voor het antwoord – (Karig) nooit meer dan eens • “Lazy talen” staan oneindige datastructuren toe. • Haskell wordt lazy geevalueerd. ML applicatief. / department of mathematics and computer science Taal & Programmeertaal • Lambda expressies als taal: S Λ = L(S) ::= V | "λ" V "." S | SS waarbij nonterminal V de variabelen genereert. • Lambda expressies als functionele programmeertaal? – Present: Functie definities en applicaties. – Afwezig constanten (bijv. geen integers). – Hoe zit het met de taalconstructies? Het blijkt dat integers (en de rest) gecodeerd kunnen worden in de λ-calculus / department of mathematics and computer science 16/34 Coderen in λ-Calculus, Church numerals • Elementen: 0 1 2 ... n = = = .. = λf x . x λf x .f x λf x .f (f x) ... λf x . f (...(f x) ...) | {z } n× • Standaardoperaties +1, +, × en ˆ: of / succ add mult exp exp = = = = = λnf x .f (nf x) λm nf x . mf (nf x) λm nf. n (mf ) λm n . n m n 6= 0 λm nf x . n mf x department of mathematics and computer science N 17/34 Verificatie succ 2 = (λnf x .f (nf x)) (λf x .f (f x)) = { afkorting } (λn .(λf x .f (nf x))) (λf x .f (f x)) { reductie (λf x .f (nf x)) [(λf x .f (f x))/n] } = (λf x .f ((λf x .f (f x))f x) ) = { afkorting; reductie } (λf x .f ((λx .f (f x)) x) ) = { nogmaals } (λf x .f (f (f x)) ) = 3 / department of mathematics and computer science 18/34 Coderen in λ-Calculus, Church Booleans • Elementen: true false B 19/34 = λx y . x = λx y . y met conditionele operator if gedefinieerd door if = λpxy.pxy • Standaardoperaties ∧, ∨ en ¬ and = λpq.pqp or = λpq.ppq not = λpxy.pyx • Verificatie: not true = (λ p x y . p y x) (λp q . p) = λx y . ((λp q . p) y x) = λx y . y Doe zelf De Morgan. • Veelgebruikte test isZero :: N → B isZero / = λ n. n (λ x . false) true department of mathematics and computer science Coderen in de λ-calculus, Church paren Paren en componenten: pair = λ x y p . p x y fst = λ p . p (λ x y . x) snd = λ p . p (λ x y . y) Verificatie fst (pair x y ) = (λ p . p (λ x y . x)) (λ p . p x y) = (λ p . p x y) (λ x y . x) = (λ x y . x) x y = x / department of mathematics and computer science 20/34 Codering van inductieve typen (****) fold van een datatype 7→ Church codering N, B, tupels zijn voorbeelden van inductieve typen. / department of mathematics and computer science 21/34 Codering van inductieve typen, 1 (****) Haskell: data Nat = Suc Nat | Zero (+1) O 0• N h , ? X N+1 h + id ? f oldN at (sOz •) 0 f oldN at (sOz •) (n + 1) s O z• X +1 = z = s (f oldN at (sOz • ) n) Codering: 0 n+1 / = λsz.z = λ s z . s (n s z) department of mathematics and computer science i.e. succ = λn s z . s (n s z) 22/34 Codering van bijbehorende folds (****) Voorbeelden: Optellen: add m n = f oldN at (succ O m• ) n add = λ m n . n succ m Code Vermenigvuldigen: mult m n = f oldN at ((+m) O 0•) n Code mult = λ m n . n (+m) 0 Machtsverheffen: exp m n = f oldN at ((×m) O 1•) n Code exp = λ m n . n (×m) 1 / department of mathematics and computer science 23/34 Codering van inductieve typen,2 (****) Haskell: data Bool = True | False B true• O f alse• h , ? X f oldBool (t•Of •) true f oldBool (t•Of •) f alse Codering: true f alse / = λtf .t = λtf .f department of mathematics and computer science 1+1 id + id ? t• O f • = t = f 1+1 24/34 Codering van inductieve typen,3 (****) data Pair x y = Pair x y P air X Y h ? Z pair X ×Y id , ? q X ×Y f oldP air (q) (pair(x, y) = q(x, y) Codering (voorkeur voor Currying): pair x y = λ q . q x y / department of mathematics and computer science 25/34 Codering van inductieve typen,4 (****) data List a = Cons a (List a) | Nil [α] (:) O []• h , ? X α × [α] + 1 id × h + id ? ⊕ O z• α×X +1 f oldList (⊕Oz •) [] = z f oldList (⊕Oz •) (x : xs) = ⊕ x (f oldList (⊕Oz •) xs) Codering: [] = λ ⊕ z.z (x : xs) = λ ⊕ z . ⊕ x (xs ⊕ z) / department of mathematics and computer science 26/34 Codering van bijbehorende folds (****) Uit de Haskell Prelude: null null [] null (_:_) null :: = = = [a] -> Bool True False f oldList ((λx y .F alse) O T rue•) Codering: null = λxs . xs (λx y . f alse) true En de rest gaat net zo! Doe zelf: Leaftrees en operaties. / department of mathematics and computer science 27/34 Programmeertaal (vervolg) 28/34 Het feit dat bepaalde grootheden gecodeerd kunnen worden in de λ-calculus houdt in dat we deze grootheden ook als constanten aan de taal zouden kunnen toevoegen zonder daarmee de aard van de taal te wijzigen. Bijvoorbeeld (toevoegen van booleans) S ::= true | false | "if" S "then" S "else" S Maar nu moeten wel de reductieregels worden uitgebreid: if true then M else N if false then M else N / department of mathematics and computer science ; M ; N Verder: taalconstructies? • Compositie (als tegenhanger van sequentie), via applicatie. • “If ... then ... else ...” via codering. “case ... of ..” en ”guards”, via “if”. • Lokale bindingen, “let” en “where” zijn ook te coderen. Bijvoorbeeld let x = e1 in e2 7→ (λx . e2) e1 mits x niet recursief bindt. • Recursie (als tegenhanger van repetitie). Via codering, als volgt: / department of mathematics and computer science 29/34 Recursie 30/34 • Recursie, van een willekeurig soort, kan uniform gecodeerd worden. • In de λ-calculus definiëert men een fixed point combinator -wordt meestal Y genoemd: – combinator: λ-term zonder vrije variabelen – fixed point: voor alle λ-termen F geldt: Y F = F (Y F ) • Er zijn meerdere fixed point combinatoren, maar de kleinste en meest bekende is die van Haskell B.Curry: Y ≡ λf . (λx .f (x x)) (λx .f (x x)) • Idee: de semantiek van een recursief gedefiniëerde functie f ∈ α → α is het (kleinste) fixed point van een functie F ∈ (α → α) → (α → α): – i.e. f = F f Voorbeelden: / department of mathematics and computer science Reconstructie F bij gegeven f 31/34 1. De faculteitsfunctie fac.n = if n = 0 then 1 else n × fac.(n − 1) • Abstraheer van n fac = λ n . if n = 0 then 1 else n × fac.(n − 1) • Abstraheer van fac in RHS fac = (λg n . if n = 0 then 1 else n × g.(n − 1)) fac i.e. fac = F fac, waarbij F = λg n . if n = 0 then 1 else n × g.(n − 1) 2. Voor gegeven f : mapf xs = if xs = [] then [] else f (hd xs) : mapf (tl xs) • Abstraheer van xs, vervolgens van mapf in RHS,dan blijkt dat mapf = F (mapf ) waarbij F = λ g xs . if xs = [] then [] else f (hd xs) : g (tl xs) / department of mathematics and computer science Maar.... • Heeft elke F : X −→ X een (kleinste) fixpoint ? / department of mathematics and computer science 32/34 Semantiek 33/34 In het algemeen niet, maar wel als F een continue functie op een CPO is. (Scott, Lehmann en Smith) • Partieel geordende verzamelingen (X, v) zo, dat iedere ω -keten een supremum heeft (compleet). • ω -keten is een monotone afbeelding γ : (N, ≤) → (X, v) • continue functies bewaren suprema van ω -ketens Features: • Nette type-vergelijkingen hebben een oplossing, en die is uniek. • (Knaster-Tarski) Elke continue functie, zeg (t i : 0 ≤ i : f i. ⊥) f , heeft een least fixpoint • Binnen typen is een (aftelbare) approximatie vanuit de bottom mogelijk. / department of mathematics and computer science Extra Opgaven 1. (****) Geef Church coderingen voor (a) (b) (c) (d) (e) (f) (+m) ∈ N → N (×m) ∈ N → N sum ∈ [N] → N (−kz) ∈ [α] → [α] map f ∈ [α] → [β], voor f ∈ α → β f ilter p ∈ [α] → [α] 34/34 2. Verifieer dat Y ≡ λf . (λx .f (x x)) (λx .f (x x)) een fixed-point combinator is. 3. Voor onderstaande functies f reconstructueer de functie F zodanig dat f =Ff (a) (b) (c) (d) / (+m) f ibonacci sum ∈ [N] → N f ilterp bij gegeven predicaat p department of mathematics and computer science