Functioneel Programmeren, 2IA05

advertisement
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
Download