Typbasierte Programmtransformation

Werbung
Typbasierte Programmtransformation
Janis Voigtländer
Technische Universität Dresden
14. Juli 2009
Funktionale Programme in Haskell
Ein Beispiel:
map f [ ]
= []
map f (a : as) = (f a) : (map f as)
1 – 2/10
Funktionale Programme in Haskell
Ein Beispiel:
map f [ ]
= []
map f (a : as) = (f a) : (map f as)
Einige Aufrufe:
map succ [1, 2, 3]
= [2, 3, 4]
1 – 3/10
Funktionale Programme in Haskell
Ein Beispiel:
map f [ ]
= []
map f (a : as) = (f a) : (map f as)
Einige Aufrufe:
map succ [1, 2, 3]
= [2, 3, 4]
map not [True, False] = [False, True]
1 – 4/10
Funktionale Programme in Haskell
Ein Beispiel:
map f [ ]
= []
map f (a : as) = (f a) : (map f as)
Einige Aufrufe:
map succ [1, 2, 3]
= [2, 3, 4]
map not [True, False] = [False, True]
map even [1, 2, 3]
= [False, True, False]
1 – 5/10
Funktionale Programme in Haskell
Ein Beispiel:
map f [ ]
= []
map f (a : as) = (f a) : (map f as)
Einige Aufrufe:
map succ [1, 2, 3]
= [2, 3, 4]
map not [True, False] = [False, True]
map even [1, 2, 3]
= [False, True, False]
map not [1, 2, 3]
1 – 6/10
Funktionale Programme in Haskell
Ein Beispiel:
map :: (α → β) → [α] → [β]
map f [ ]
= []
map f (a : as) = (f a) : (map f as)
Einige Aufrufe:
map succ [1, 2, 3]
= [2, 3, 4]
map not [True, False] = [False, True]
map even [1, 2, 3]
= [False, True, False]
map not [1, 2, 3]
1 – 7/10
Funktionale Programme in Haskell
Ein Beispiel:
map :: (α → β) → [α] → [β]
map f [ ]
= []
map f (a : as) = (f a) : (map f as)
Einige Aufrufe:
map succ [1, 2, 3]
= [2, 3, 4]
— α, β 7→ Int, Int
map not [True, False] = [False, True]
— α, β 7→ Bool, Bool
map even [1, 2, 3]
— α, β 7→ Int, Bool
= [False, True, False]
map not [1, 2, 3]
1 – 8/10
Funktionale Programme in Haskell
Ein Beispiel:
map :: (α → β) → [α] → [β]
map f [ ]
= []
map f (a : as) = (f a) : (map f as)
Einige Aufrufe:
map succ [1, 2, 3]
= [2, 3, 4]
— α, β 7→ Int, Int
map not [True, False] = [False, True]
— α, β 7→ Bool, Bool
map even [1, 2, 3]
— α, β 7→ Int, Bool
map not [1, 2, 3]
= [False, True, False]
zur Compile-Zeit zurückgewiesen
1 – 9/10
Funktionale Programme in Haskell
Ein Beispiel:
map :: (α → β) → [α] → [β]
Einige Aufrufe:
map succ [1, 2, 3]
= [2, 3, 4]
— α, β 7→ Int, Int
map not [True, False] = [False, True]
— α, β 7→ Bool, Bool
map even [1, 2, 3]
— α, β 7→ Int, Bool
map not [1, 2, 3]
= [False, True, False]
zur Compile-Zeit zurückgewiesen
1 – 10/10
Komposition von Funktionen
Ein weiteres Beispiel:
filter :: (α → Bool) → [α] → [α]
filter p [ ]
= []
filter p (a : as) | p a
= a : (filter p as)
| otherwise = filter p as
2 – 11/14
Komposition von Funktionen
Ein weiteres Beispiel:
filter :: (α → Bool) → [α] → [α]
filter p [ ]
= []
filter p (a : as) | p a
= a : (filter p as)
| otherwise = filter p as
Problem: Ausdrücke wie map f (filter p l ) erfordern
Konstruktion von Zwischenergebnissen.
2 – 12/14
Komposition von Funktionen
Ein weiteres Beispiel:
filter :: (α → Bool) → [α] → [α]
filter p [ ]
= []
filter p (a : as) | p a
= a : (filter p as)
| otherwise = filter p as
Problem: Ausdrücke wie map f (filter p l ) ∗ erfordern
Konstruktion von Zwischenergebnissen.
∗
sum [f x | x ← [1..n], p x]
sum (map f (filter p (enumFromTo 1 n)))
2 – 13/14
Komposition von Funktionen
Ein weiteres Beispiel:
filter :: (α → Bool) → [α] → [α]
filter p [ ]
= []
filter p (a : as) | p a
= a : (filter p as)
| otherwise = filter p as
Problem: Ausdrücke wie map f (filter p l ) ∗ erfordern
Konstruktion von Zwischenergebnissen.
Lösung?: Explizite Regeln
map f (filter p
filter p (map f
map f1 (map f2
filter p1 (filter p2
∗
sum [f x | x ← [1..n], p x]
l)
l)
l)
l)
···
···
···
···
sum (map f (filter p (enumFromTo 1 n)))
2 – 14/14
Komposition von Funktionen
Ein weiteres Beispiel:
filter :: (α → Bool) → [α] → [α]
filter p [ ]
= []
filter p (a : as) | p a
= a : (filter p as)
| otherwise = filter p as
Für jede Wahl von p, f und l gilt:
filter p (map f l ) = map f (filter (p ◦ f ) l )
Beweisbar per Induktion.
3 – 15/19
Komposition von Funktionen
Ein weiteres Beispiel:
filter :: (α → Bool) → [α] → [α]
filter p [ ]
= []
filter p (a : as) | p a
= a : (filter p as)
| otherwise = filter p as
Für jede Wahl von p, f und l gilt:
filter p (map f l ) = map f (filter (p ◦ f ) l )
Beweisbar per Induktion.
Oder als freies Theorem“ [Wadler, FPCA’89].
”
3 – 16/19
Komposition von Funktionen
Ein weiteres Beispiel:
filter :: (α → Bool) → [α] → [α]
Für jede Wahl von p, f und l gilt:
filter p (map f l ) = map f (filter (p ◦ f ) l )
Beweisbar per Induktion.
Oder als freies Theorem“ [Wadler, FPCA’89].
”
3 – 17/19
Komposition von Funktionen
Ein weiteres Beispiel:
filter :: (α → Bool) → [α] → [α]
takeWhile :: (α → Bool) → [α] → [α]
Für jede Wahl von p, f und l gilt:
filter p (map f l ) = map f (filter (p ◦ f ) l )
takeWhile p (map f l ) = map f (takeWhile (p ◦ f ) l )
3 – 18/19
Komposition von Funktionen
Ein weiteres Beispiel:
filter :: (α → Bool) → [α] → [α]
takeWhile :: (α → Bool) → [α] → [α]
g :: (α → Bool) → [α] → [α]
Für jede Wahl von p, f und l gilt:
filter p (map f l ) = map f (filter (p ◦ f ) l )
takeWhile p (map f l ) = map f (takeWhile (p ◦ f ) l )
g p (map f l ) = map f (g (p ◦ f ) l )
3 – 19/19
Short Cut Fusion [Gill et al., FPCA’93]
Schreibe Listenkonsumenten mittels foldr:
:
a1
foldr c n ( a2
c
:
a1
X
) =
a2
c
X
:
ak
c
[]
ak
n
4 – 20/22
Short Cut Fusion [Gill et al., FPCA’93]
Schreibe Listenkonsumenten mittels foldr:
:
a1
foldr c n ( a2
c
:
a1
X
) =
a2
c
X
:
ak
c
[]
ak
n
Schreibe Listenerzeuger mittels build:
build :: (∀β. (α → β → β) → β → β) → [α]
build prod = prod (:) [ ]
4 – 21/22
Short Cut Fusion [Gill et al., FPCA’93]
Schreibe Listenkonsumenten mittels foldr:
:
a1
foldr c n ( a2
c
:
a1
X
) =
a2
c
X
:
ak
c
[]
ak
n
Schreibe Listenerzeuger mittels build:
build :: (∀β. (α → β → β) → β → β) → [α]
build prod = prod (:) [ ]
4 – 22/22
Short Cut Fusion [Gill et al., FPCA’93]
Jedes derart polymorphe prod muss einer Funktion der folgenden
Form entsprechen, für feste k ≥ 0 und a1 , . . . , ak :
c
a1
prod
= λc n →
a2
c
X
c
ak
n
5 – 23/24
Short Cut Fusion [Gill et al., FPCA’93]
Jedes derart polymorphe prod muss einer Funktion der folgenden
Form entsprechen, für feste k ≥ 0 und a1 , . . . , ak :
c
a1
prod
= λc n →
a2
c
X
c
ak
n
Zum Beispiel:
filter :: (α → Bool) → [α] → [α]
filter p as = build (λc n → let c ′ a r | p a
=c ar
| otherwise = r
in foldr c ′ n as)
5 – 24/24
Short Cut Fusion [Gill et al., FPCA’93]
Benutze folgende Regel:
foldr c n (build prod)
prod c n
6 – 25/31
Short Cut Fusion [Gill et al., FPCA’93]
Benutze folgende Regel:
foldr c ′ n′ (build prod)
prod c ′ n′
6 – 26/31
Short Cut Fusion [Gill et al., FPCA’93]
Benutze folgende Regel:
foldr c ′ n′ (build prod)
prod c ′ n′
Zur Rechtfertigung:
foldr c ′ n′ (build prod)
6 – 27/31
Short Cut Fusion [Gill et al., FPCA’93]
Benutze folgende Regel:
foldr c ′ n′ (build prod)
prod c ′ n′
Zur Rechtfertigung:
c
a1
foldr c ′ n′ (build (λc n →
a2
c
))
X
c
ak
n
6 – 28/31
Short Cut Fusion [Gill et al., FPCA’93]
Benutze folgende Regel:
foldr c ′ n′ (build prod)
prod c ′ n′
Zur Rechtfertigung:
:
a1
foldr c ′ n′ ( a2
:
)
X
:
ak
[]
6 – 29/31
Short Cut Fusion [Gill et al., FPCA’93]
Benutze folgende Regel:
foldr c ′ n′ (build prod)
prod c ′ n′
Zur Rechtfertigung:
c′
a1
c′
a2
X
c′
ak
n′
6 – 30/31
Short Cut Fusion [Gill et al., FPCA’93]
Benutze folgende Regel:
foldr c ′ n′ (build prod)
prod c ′ n′
Zur Rechtfertigung:
c′
a1
c′
a2
X
c′
ak
n′
Für den Compiler (GHC):
{−# RULES “foldr/build”
∀(prod :: ∀β. (α → β → β) → β → β) c n.
foldr c n (build prod) = prod c n
#−}
6 – 31/31
Die destroy-Funktion [Svenningsson, ICFP’02]
Als Alternative zu foldr:
destroy :: (∀β. (β → Maybe (α, β)) → β → γ) → [α] → γ
destroy cons as = cons match as
wobei:
data Maybe τ = Nothing | Just τ
match :: [α] → Maybe (α, [α])
match [ ]
= Nothing
match (a : as) = Just (a, as)
7 – 32/33
Die destroy-Funktion [Svenningsson, ICFP’02]
Als Alternative zu foldr:
destroy :: (∀β. (β → Maybe (α, β)) → β → γ) → [α] → γ
destroy cons as = cons match as
wobei:
data Maybe τ = Nothing | Just τ
match :: [α] → Maybe (α, [α])
match [ ]
= Nothing
match (a : as) = Just (a, as)
Zum Beispiel:
zip :: [α] → [β] → [(α, β)]
zip as bs = destroy (λp x → destroy (λq y → zipD p q x y ) bs) as
where zipD = λp q x y →
case (p x, q y ) of
(Nothing , Nothing ) → [ ]
(Just (a, x ′ ), Just (b, y ′ )) → (a, b) : (zipD p q x ′ y ′ )
7 – 33/33
Eine destroy/build-Regel [V., PEPM’08]
Laut Definitionen ist
destroy cons (build prod )
...
8 – 34/37
Eine destroy/build-Regel [V., PEPM’08]
Laut Definitionen ist
destroy cons (build prod )
das Gleiche wie
cons match (prod (:) [ ]) ,
wobei:
match [ ]
= Nothing
match (a : as) = Just (a, as)
8 – 35/37
Eine destroy/build-Regel [V., PEPM’08]
Laut Definitionen ist
destroy cons (build prod )
das Gleiche wie
cons match (prod (:) [ ]) ,
wobei:
match [ ]
= Nothing
match (a : as) = Just (a, as)
Warum dann nicht einfach
destroy cons (build prod )
cons id (prod (λa as → Just (a, as)) Nothing) ?
8 – 36/37
Eine destroy/build-Regel [V., PEPM’08]
Laut Definitionen ist
destroy cons (build prod )
das Gleiche wie
cons match (prod (:) [ ]) ,
wobei:
match [ ]
= Nothing
match (a : as) = Just (a, as)
Warum dann nicht einfach
destroy cons (build prod )
cons id (prod (λa as → Just (a, as)) Nothing) ?
Erhält diese Regel die Semantik?
8 – 37/37
Beweis der Korrektheit
Alles, was wir über cons und prod wissen, sind ihre Typen:
cons :: ∀β. (β → Maybe (T1 , β)) → β → T2
und
prod :: ∀β. (T1 → β → β) → β → β
9 – 38/39
Beweis der Korrektheit
Alles, was wir über cons und prod wissen, sind ihre Typen:
cons :: ∀β. (β → Maybe (T1 , β)) → β → T2
und
prod :: ∀β. (T1 → β → β) → β → β
Aber dies könnte reichen, Dank freier Theoreme!
Im Folgenden, eine Beweisskizze.
9 – 39/39
Wo beginnen?
Das freie Theorem für
cons :: ∀β. (β → Maybe (T1 , β)) → β → T2
ist:
∀τ1 , τ2 , R ⊆ τ1 × τ2 , R strict, continuous, and bottom-reflecting.
∀p :: τ1 → Maybe (T1 , τ1 ), q :: τ2 → Maybe (T1 , τ2 ).
(p 6= ⊥ ⇔ q 6= ⊥)
∧ (∀(x, y ) ∈ R. (p x, q y ) ∈ liftMaybe (lift(,) (id, R)))
⇒ ∀(z, v ) ∈ R. cons p z = cons q v
10 – 40/48
Wo beginnen?
Das freie Theorem für
cons :: ∀β. (β → Maybe (T1 , β)) → β → T2
ist:
∀τ1 , τ2 , R ⊆ τ1 × τ2 , R strict, continuous, and bottom-reflecting.
∀p :: τ1 → Maybe (T1 , τ1 ), q :: τ2 → Maybe (T1 , τ2 ).
(p 6= ⊥ ⇔ q 6= ⊥)
∧ (∀(x, y ) ∈ R. (p x, q y ) ∈ liftMaybe (lift(,) (id, R)))
⇒ ∀(z, v ) ∈ R. cons p z = cons q v
Zur Erinnerung, wir wollen beweisen:
cons match (prod (:) [ ])
=
cons id (prod (λa as → Just (a, as)) Nothing)
10 – 41/48
Wo beginnen?
Das freie Theorem für
cons :: ∀β. (β → Maybe (T1 , β)) → β → T2
ist:
[Johann & V., POPL’04]
∀τ1 , τ2 , R ⊆ τ1 × τ2 , R strict, continuous, and bottom-reflecting.
∀p :: τ1 → Maybe (T1 , τ1 ), q :: τ2 → Maybe (T1 , τ2 ).
(p 6= ⊥ ⇔ q 6= ⊥)
∧ (∀(x, y ) ∈ R. (p x, q y ) ∈ liftMaybe (lift(,) (id, R)))
⇒ ∀(z, v ) ∈ R. cons p z = cons q v
Zur Erinnerung, wir wollen beweisen:
cons match (prod (:) [ ])
=
cons id (prod (λa as → Just (a, as)) Nothing)
10 – 42/48
Wo beginnen?
Das freie Theorem für
cons :: ∀β. (β → Maybe (T1 , β)) → β → T2
ist:
[Johann & V., POPL’04]
∀τ1 , τ2 , R ⊆ τ1 × τ2 , R strict, continuous, and bottom-reflecting.
∀p :: τ1 → Maybe (T1 , τ1 ), q :: τ2 → Maybe (T1 , τ2 ).
(p 6= ⊥ ⇔ q 6= ⊥)
∧ (∀(x, y ) ∈ R. (p x, q y ) ∈ liftMaybe (lift(,) (id, R)))
⇒ ∀(z, v ) ∈ R. cons p z = cons q v
Zur Erinnerung, wir wollen beweisen:
cons match (prod (:) [ ])
=
cons id (prod (λa as → Just (a, as)) Nothing)
10 – 43/48
Wo beginnen?
Das freie Theorem für
cons :: ∀β. (β → Maybe (T1 , β)) → β → T2 ,
spezialisiert auf die Ebene von Funktionen, ist:
∀τ1 , τ2 , f :: τ1 → τ2 , f strict and total.
∀p :: τ1 → Maybe (T1 , τ1 ), q :: τ2 → Maybe (T1 , τ2 ).
(p 6= ⊥ ⇔ q 6= ⊥)
∧ (∀x :: τ1 . (p x, q (f x)) ∈ liftMaybe (lift(,) (id, f )))
⇒ ∀y :: τ1 . cons p y = cons q (f y )
Zur Erinnerung, wir wollen beweisen:
cons match (prod (:) [ ])
=
cons id (prod (λa as → Just (a, as)) Nothing)
10 – 44/48
Wo beginnen?
Das freie Theorem für
cons :: ∀β. (β → Maybe (T1 , β)) → β → T2 ,
spezialisiert auf die Ebene von Funktionen, ist:
∀τ1 , τ2 , f :: τ1 → τ2 , f strict and total.
∀p :: τ1 → Maybe (T1 , τ1 ), q :: τ2 → Maybe (T1 , τ2 ).
(p 6= ⊥ ⇔ q 6= ⊥)
∧ (∀x :: τ1 . (p x, q (f x)) ∈ liftMaybe (lift(,) (id, f )))
⇒ ∀y :: τ1 . cons p y = cons q (f y )
Zur Erinnerung, wir wollen beweisen:
cons match (prod (:) [ ])
=
cons id (prod (λa as → Just (a, as)) Nothing)
10 – 45/48
Wo beginnen?
Das freie Theorem für
cons :: ∀β. (β → Maybe (T1 , β)) → β → T2 ,
spezialisiert auf die Ebene von Funktionen, ist:
∀τ1 , τ2 , f :: τ1 → τ2 , f strict and total.
∀p :: τ1 → Maybe (T1 , τ1 ), q :: τ2 → Maybe (T1 , τ2 ).
(p 6= ⊥ ⇔ q 6= ⊥)
∧ (∀x :: τ1 . (p x, q (f x)) ∈ liftMaybe (lift(,) (id, f )))
⇒ ∀y :: τ1 . cons p y = cons q (f y )
Zur Erinnerung, wir wollen beweisen:
cons match (prod (:) [ ])
=
cons id (prod (λa as → Just (a, as)) Nothing)
10 – 46/48
Wo beginnen?
Das freie Theorem für
cons :: ∀β. (β → Maybe (T1 , β)) → β → T2 ,
spezialisiert auf die Ebene von Funktionen, ist:
∀τ1 , τ2 , f :: τ1 → τ2 , f strict and total.
∀p :: τ1 → Maybe (T1 , τ1 ), q :: τ2 → Maybe (T1 , τ2 ).
(p 6= ⊥ ⇔ q 6= ⊥)
∧ (∀x :: τ1 . (p x, q (f x)) ∈ liftMaybe (lift(,) (id, f )))
⇒ ∀y :: τ1 . cons p y = cons q (f y )
Zur Erinnerung, wir wollen beweisen:
cons match (prod (:) [ ])
=
cons id (prod (λa as → Just (a, as)) Nothing)
10 – 47/48
Wo beginnen?
Das freie Theorem für
cons :: ∀β. (β → Maybe (T1 , β)) → β → T2 ,
spezialisiert auf die Ebene von Funktionen, ist:
∀τ1 , τ2 , f :: τ1 → τ2 , f strict and total.
∀p :: τ1 → Maybe (T1 , τ1 ), q :: τ2 → Maybe (T1 , τ2 ).
(p 6= ⊥ ⇔ q 6= ⊥)
∧ (∀x :: τ1 . (p x, q (f x)) ∈ liftMaybe (lift(,) (id, f )))
⇒ ∀y :: τ1 . cons p y = cons q (f y )
Zur Erinnerung, wir wollen beweisen:
cons match (prod (:) [ ])
=
cons id (prod (λa as → Just (a, as)) Nothing)
10 – 48/48
Wie weiter?
Alles, was wir brauchen, ist eine Funktion f so dass:
1. f ist strict und total
2. ∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f ))
3. f (prod (:) [ ]) = prod (λa as → Just (a, as)) Nothing
(Hinweis: match 6= ⊥ ⇔ id 6= ⊥ ist trivial erfüllt.)
11 – 49/55
Wie weiter?
Alles, was wir brauchen, ist eine Funktion f so dass:
1. f ist strict und total
2. ∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f ))
3. f (prod (:) [ ]) = prod (λa as → Just (a, as)) Nothing
11 – 50/55
Wie weiter?
Alles, was wir brauchen, ist eine Funktion f so dass:
1. f ist strict und total
2. ∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f ))
3. f (prod (:) [ ]) = prod (λa as → Just (a, as)) Nothing
Das freie Theorem für
prod :: ∀β. (T1 → β → β) → β → β
ist:
∀τ1 , τ2 , R ⊆ τ1 × τ2 , R strict, continuous, and bottom-reflecting.
∀p :: T1 → τ1 → τ1 , q :: T1 → τ2 → τ2 .
(p 6= ⊥ ⇔ q 6= ⊥)
∧ (∀x :: T1 . (p x 6= ⊥ ⇔ q x 6= ⊥)
∧ ∀(y , z) ∈ R. (p x y , q x z) ∈ R)
⇒ ∀(v , w ) ∈ R. (prod p v , prod q w ) ∈ R
11 – 51/55
Wie weiter?
Alles, was wir brauchen, ist eine Funktion f so dass:
1. f ist strict und total
2. ∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f ))
3. f (prod (:) [ ]) = prod (λa as → Just (a, as)) Nothing
Das freie Theorem für
prod :: ∀β. (T1 → β → β) → β → β ,
spezialisiert auf die Ebene von Funktionen, ist:
∀τ1 , τ2 , f :: τ1 → τ2 , f strict and total.
∀p :: T1 → τ1 → τ1 , q :: T1 → τ2 → τ2 .
(p 6= ⊥ ⇔ q 6= ⊥)
∧ (∀x :: T1 . (p x 6= ⊥ ⇔ q x 6= ⊥)
∧ ∀y :: τ1 . f (p x y ) = q x (f y ))
⇒ ∀z :: τ1 . f (prod p z) = prod q (f z)
11 – 52/55
Wie weiter?
Alles, was wir brauchen, ist eine Funktion f so dass:
1. f ist strict und total
2. ∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f ))
3. f (prod (:) [ ]) = prod (λa as → Just (a, as)) Nothing
Das freie Theorem für
prod :: ∀β. (T1 → β → β) → β → β ,
spezialisiert auf die Ebene von Funktionen, ist:
∀τ1 , τ2 , f :: τ1 → τ2 , f strict and total.
∀p :: T1 → τ1 → τ1 , q :: T1 → τ2 → τ2 .
(p 6= ⊥ ⇔ q 6= ⊥)
∧ (∀x :: T1 . (p x 6= ⊥ ⇔ q x 6= ⊥)
∧ ∀y :: τ1 . f (p x y ) = q x (f y ))
⇒ ∀z :: τ1 . f (prod p z) = prod q (f z)
11 – 53/55
Wie weiter?
Alles, was wir brauchen, ist eine Funktion f so dass:
1. f ist strict und total
2. ∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f ))
3. f (prod (:) [ ]) = prod (λa as → Just (a, as)) Nothing
Das freie Theorem für
prod :: ∀β. (T1 → β → β) → β → β ,
spezialisiert auf die Ebene von Funktionen, ist:
∀τ1 , τ2 , f :: τ1 → τ2 , f strict and total.
∀p :: T1 → τ1 → τ1 , q :: T1 → τ2 → τ2 .
(p 6= ⊥ ⇔ q 6= ⊥)
∧ (∀x :: T1 . (p x 6= ⊥ ⇔ q x 6= ⊥)
∧ ∀y :: τ1 . f (p x y ) = q x (f y ))
⇒ ∀z :: τ1 . f (prod p z) = prod q (f z)
11 – 54/55
Wie weiter?
Alles, was wir brauchen, ist eine Funktion f so dass:
1. f ist strict und total
2. ∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f ))
3. f (prod (:) [ ]) = prod (λa as → Just (a, as)) Nothing
Das freie Theorem für
prod :: ∀β. (T1 → β → β) → β → β ,
spezialisiert auf die Ebene von Funktionen, ist:
∀τ1 , τ2 , f :: τ1 → τ2 , f strict and total.
∀p :: T1 → τ1 → τ1 , q :: T1 → τ2 → τ2 .
(p 6= ⊥ ⇔ q 6= ⊥)
∧ (∀x :: T1 . (p x 6= ⊥ ⇔ q x 6= ⊥)
∧ ∀y :: τ1 . f (p x y ) = q x (f y ))
⇒ ∀z :: τ1 . f (prod p z) = prod q (f z)
11 – 55/55
Fast geschafft
Alles, was wir brauchen, ist eine Funktion f so dass:
1. f ist strict und total
2. ∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f ))
3. ∀x :: T1 , y :: [T1 ]. f ((:) x y ) = (λa as → Just (a, as)) x (f y )
4. f [ ] = Nothing
(Hinweis: die =
6 ⊥“-Bedingungen sind wieder trivial erfüllt.)
”
12 – 56/61
Fast geschafft
Alles, was wir brauchen, ist eine Funktion f so dass:
1. f ist strict und total
2. ∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f ))
3. ∀x :: T1 , y :: [T1 ]. f ((:) x y ) = (λa as → Just (a, as)) x (f y )
4. f [ ] = Nothing
12 – 57/61
Fast geschafft
Alles, was wir brauchen, ist eine Funktion f so dass:
1. f ist strict und total
2. ∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f ))
3. ∀x :: T1 , y :: [T1 ]. f ((:) x y ) = (λa as → Just (a, as)) x (f y )
4. f [ ] = Nothing
Die letzten beiden Bedingungen lassen keine andere Wahl als:
f []
= Nothing
f (x : y ) = Just (x, f y )
12 – 58/61
Fast geschafft
Alles, was wir brauchen, ist:
1. f ist strict und total
2. ∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f ))
Die letzten beiden Bedingungen lassen keine andere Wahl als:
f []
= Nothing
f (x : y ) = Just (x, f y )
12 – 59/61
Fast geschafft
Alles, was wir brauchen, ist:
1. f ist strict und total
2. ∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f ))
f []
= Nothing
f (x : y ) = Just (x, f y )
Dieses f ist strict und total!
12 – 60/61
Fast geschafft
2. ∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f )) ?
f []
= Nothing
f (x : y ) = Just (x, f y )
12 – 61/61
Schließlich . . .
Wir haben:
liftMaybe (lift(,) (id, f )) = {(⊥, ⊥), (Nothing, Nothing)} ∪
{(Just x1 , Just y1 ) | (x1 , y1 ) ∈ lift(,) (id, f )}
lift(,) (id, f ) = {(⊥, ⊥)} ∪ {((x1 , x2 ), (y1 , y2 )) | x1 = y1 ∧ f x2 = y2 }
13 – 62/69
Schließlich . . .
Wir haben:
liftMaybe (lift(,) (id, f )) = {(⊥, ⊥), (Nothing, Nothing)} ∪
{(Just x1 , Just y1 ) | (x1 , y1 ) ∈ lift(,) (id, f )}
lift(,) (id, f ) = {(⊥, ⊥)} ∪ {((x1 , x2 ), (y1 , y2 )) | x1 = y1 ∧ f x2 = y2 }
Um zu zeigen, dass
∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f )) ,
13 – 63/69
Schließlich . . .
Wir haben:
liftMaybe (lift(,) (id, f )) = {(⊥, ⊥), (Nothing, Nothing)} ∪
{(Just x1 , Just y1 ) | (x1 , y1 ) ∈ lift(,) (id, f )}
lift(,) (id, f ) = {(⊥, ⊥)} ∪ {((x1 , x2 ), (y1 , y2 )) | x1 = y1 ∧ f x2 = y2 }
Um zu zeigen, dass
∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f )) ,
untersuchen wir alle Fälle für Eingaben von match und f ,
unter Verwendung der Definitionen:
match [ ]
= Nothing
match (a : as) = Just (a, as)
f []
= Nothing
f (x : y ) = Just (x, f y )
13 – 64/69
Schließlich . . .
Wir haben:
liftMaybe (lift(,) (id, f )) = {(⊥, ⊥), (Nothing, Nothing)} ∪
{(Just x1 , Just y1 ) | (x1 , y1 ) ∈ lift(,) (id, f )}
lift(,) (id, f ) = {(⊥, ⊥)} ∪ {((x1 , x2 ), (y1 , y2 )) | x1 = y1 ∧ f x2 = y2 }
Um zu zeigen, dass
∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f )) ,
untersuchen wir alle Fälle für Eingaben von match und f ,
unter Verwendung der Definitionen:
match [ ]
= Nothing
match (a : as) = Just (a, as)
f []
= Nothing
f (x : y ) = Just (x, f y )
13 – 65/69
Schließlich . . .
Wir haben:
liftMaybe (lift(,) (id, f )) = {(⊥, ⊥), (Nothing, Nothing)} ∪
{(Just x1 , Just y1 ) | (x1 , y1 ) ∈ lift(,) (id, f )}
lift(,) (id, f ) = {(⊥, ⊥)} ∪ {((x1 , x2 ), (y1 , y2 )) | x1 = y1 ∧ f x2 = y2 }
Um zu zeigen, dass
∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f )) ,
untersuchen wir alle Fälle für Eingaben von match und f ,
unter Verwendung der Definitionen:
match [ ]
= Nothing
match (a : as) = Just (a, as)
f []
= Nothing
f (x : y ) = Just (x, f y )
13 – 66/69
Schließlich . . .
Wir haben:
liftMaybe (lift(,) (id, f )) = {(⊥, ⊥), (Nothing, Nothing)} ∪
{(Just x1 , Just y1 ) | (x1 , y1 ) ∈ lift(,) (id, f )}
lift(,) (id, f ) = {(⊥, ⊥)} ∪ {((x1 , x2 ), (y1 , y2 )) | x1 = y1 ∧ f x2 = y2 }
Um zu zeigen, dass
∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f )) ,
untersuchen wir alle Fälle für Eingaben von match und f ,
unter Verwendung der Definitionen:
match [ ]
= Nothing
match (a : as) = Just (a, as)
f []
= Nothing
f (x : y ) = Just (x, f y )
13 – 67/69
Schließlich . . .
Wir haben:
liftMaybe (lift(,) (id, f )) = {(⊥, ⊥), (Nothing, Nothing)} ∪
{(Just x1 , Just y1 ) | (x1 , y1 ) ∈ lift(,) (id, f )}
lift(,) (id, f ) = {(⊥, ⊥)} ∪ {((x1 , x2 ), (y1 , y2 )) | x1 = y1 ∧ f x2 = y2 }
Um zu zeigen, dass
∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f )) ,
untersuchen wir alle Fälle für Eingaben von match und f ,
unter Verwendung der Definitionen:
match [ ]
= Nothing
match (a : as) = Just (a, as)
f []
= Nothing
f (x : y ) = Just (x, f y )
13 – 68/69
Schließlich . . .
Wir haben:
liftMaybe (lift(,) (id, f )) = {(⊥, ⊥), (Nothing, Nothing)} ∪
{(Just x1 , Just y1 ) | (x1 , y1 ) ∈ lift(,) (id, f )}
lift(,) (id, f ) = {(⊥, ⊥)} ∪ {((x1 , x2 ), (y1 , y2 )) | x1 = y1 ∧ f x2 = y2 }
Um zu zeigen, dass
∀x :: [T1 ]. (match x, id (f x)) ∈ liftMaybe (lift(,) (id, f )) ,
untersuchen wir alle Fälle für Eingaben von match und f ,
unter Verwendung der Definitionen:
match [ ]
= Nothing
match (a : as) = Just (a, as)
f []
= Nothing
f (x : y ) = Just (x, f y )
Fertig!
13 – 69/69
Fazit
Typangaben:
◮
schränken das Verhalten von Programmen ein
◮
erlauben daher die Herleitung von Aussagen über Programme
14 – 70/75
Fazit
Typangaben:
◮
schränken das Verhalten von Programmen ein
◮
erlauben daher die Herleitung von Aussagen über Programme
Erhaltene Programmtransformationen:
◮
bauen insbesondere auf Polymorphismus und Higher-Order“
”
14 – 71/75
Fazit
Typangaben:
◮
schränken das Verhalten von Programmen ein
◮
erlauben daher die Herleitung von Aussagen über Programme
Erhaltene Programmtransformationen:
◮
◮
bauen insbesondere auf Polymorphismus und Higher-Order“
”
können nicht-triviale Nebenbedingungen haben
14 – 72/75
Fazit
Typangaben:
◮
schränken das Verhalten von Programmen ein
◮
erlauben daher die Herleitung von Aussagen über Programme
Erhaltene Programmtransformationen:
◮
◮
bauen insbesondere auf Polymorphismus und Higher-Order“
”
können nicht-triviale Nebenbedingungen haben
Korrektheitsbeweise:
◮
sind zum Teil automatisierbar
◮
wo nicht, zumindest systematisch/zielgetrieben
14 – 73/75
Fazit
Typangaben:
◮
schränken das Verhalten von Programmen ein
◮
erlauben daher die Herleitung von Aussagen über Programme
Erhaltene Programmtransformationen:
◮
◮
bauen insbesondere auf Polymorphismus und Higher-Order“
”
können nicht-triviale Nebenbedingungen haben
Korrektheitsbeweise:
◮
sind zum Teil automatisierbar
◮
wo nicht, zumindest systematisch/zielgetrieben
(ähnlich für andere Transformationen [V., FLOPS’08])
14 – 74/75
Fazit
Typangaben:
◮
schränken das Verhalten von Programmen ein
◮
erlauben daher die Herleitung von Aussagen über Programme
Erhaltene Programmtransformationen:
◮
◮
bauen insbesondere auf Polymorphismus und Higher-Order“
”
können nicht-triviale Nebenbedingungen haben
Korrektheitsbeweise:
◮
sind zum Teil automatisierbar
◮
wo nicht, zumindest systematisch/zielgetrieben
(ähnlich für andere Transformationen [V., FLOPS’08])
Weiter von Interesse:
◮
größere Abdeckung von Sprachkonstrukten
◮
noch ausdrucksstärkere Typsysteme
14 – 75/75
Literatur I
A. Gill, J. Launchbury, and S.L. Peyton Jones.
A short cut to deforestation.
In Functional Programming Languages and Computer
Architecture, Proceedings, pages 223–232. ACM Press, 1993.
P. Johann and J. Voigtländer.
Free theorems in the presence of seq.
In Principles of Programming Languages, Proceedings, pages
99–110. ACM Press, 2004.
P. Johann and J. Voigtländer.
A family of syntactic logical relations for the semantics of
Haskell-like languages.
Information and Computation, 207(2):341–368, 2009.
15 – 76/78
Literatur II
S.L. Peyton Jones, A. Tolmach, and C.A.R. Hoare.
Playing by the rules: Rewriting as a practical optimisation
technique in GHC.
In Haskell Workshop, Proceedings, pages 203–233, 2001.
F. Stenger and J. Voigtländer.
Parametricity for Haskell with imprecise error semantics.
In Typed Lambda Calculi and Applications, Proceedings,
volume 5608 of LNCS, pages 294–308. Springer-Verlag, 2009.
J. Svenningsson.
Shortcut fusion for accumulating parameters & zip-like
functions.
In International Conference on Functional Programming,
Proceedings, pages 124–132. ACM Press, 2002.
16 – 77/78
Literatur III
J. Voigtländer.
Proving correctness via free theorems: The case of the
destroy/build-rule.
In Partial Evaluation and Program Manipulation, Proceedings,
pages 13–20. ACM Press, 2008.
J. Voigtländer.
Semantics and pragmatics of new shortcut fusion rules.
In Functional and Logic Programming, Proceedings, volume
4989 of LNCS, pages 163–179. Springer-Verlag, 2008.
P. Wadler.
Theorems for free!
In Functional Programming Languages and Computer
Architecture, Proceedings, pages 347–359. ACM Press, 1989.
17 – 78/78
Herunterladen