Errors in Haskell

Werbung
Errors in Haskell
• let average xs = div (sum xs) (length xs)
in average [ ]
1
Errors in Haskell
• let average xs = div (sum xs) (length xs)
in average [ ]
• let tail (x : xs) = xs
in tail [ ]
1
Errors in Haskell
• let average xs = div (sum xs) (length xs)
in average [ ]
• let tail (x : xs) = xs
in tail [ ]
• if · · · then error “some string” else · · ·
1
Errors in Haskell
• let average xs = div (sum xs) (length xs)
in average [ ]
• let tail (x : xs) = xs
in tail [ ]
• if · · · then error “some string” else · · ·
• let loop = loop
in loop
1
Errors in Haskell
• let average xs = div (sum xs) (length xs)
in average [ ]
• let tail (x : xs) = xs
in tail [ ]
• if · · · then error “some string” else · · ·
• let loop = loop
in loop
Traditionell, oft alle Fehlerursachen unter „⊥“ subsumiert.
1
Errors in Haskell
• let average xs = div (sum xs) (length xs)
in average [ ]
• let tail (x : xs) = xs
in tail [ ]
• if · · · then error “some string” else · · ·
• let loop = loop
in loop
Traditionell, oft alle Fehlerursachen unter „⊥“ subsumiert.
Besser, feinere Unterscheidung. Etwa wie folgt:
Ok v : nicht fehlerbehaftet
Bad “· · · ” : endlich fehlerbehaftet
⊥ : nicht terminierend
1
Fortpflanzung von Fehlern
• tail [1/0, 2.5]
Ok ((Ok 2.5) : (Ok [ ]))
2
Fortpflanzung von Fehlern
• tail [1/0, 2.5]
Ok ((Ok 2.5) : (Ok [ ]))
• (λx → 3) (error “· · · ”)
Ok 3
2
Fortpflanzung von Fehlern
• tail [1/0, 2.5]
Ok ((Ok 2.5) : (Ok [ ]))
• (λx → 3) (error “· · · ”)
• (error s) (· · · )
Ok 3
Bad s
2
Fortpflanzung von Fehlern
• tail [1/0, 2.5]
Ok ((Ok 2.5) : (Ok [ ]))
• (λx → 3) (error “· · · ”)
• (error s) (· · · )
Ok 3
Bad s
• case (error s) of {· · · }
Bad s
2
Fortpflanzung von Fehlern
• tail [1/0, 2.5]
Ok ((Ok 2.5) : (Ok [ ]))
• (λx → 3) (error “· · · ”)
• (error s) (· · · )
Ok 3
Bad s
• case (error s) of {· · · }
Bad s
• (error s1 ) + (error s2 )
???
2
Fortpflanzung von Fehlern
• tail [1/0, 2.5]
Ok ((Ok 2.5) : (Ok [ ]))
• (λx → 3) (error “· · · ”)
• (error s) (· · · )
Ok 3
Bad s
• case (error s) of {· · · }
Bad s
• (error s1 ) + (error s2 )
???
Abhängigkeit von Auswertungsreihenfolge führt zu erheblichen
Einschränkungen der Implementationsfreiheit!
2
Imprecise Error Semantics [Peyton Jones et al. 1999]
Grundidee:
Ok v : nicht fehlerbehaftet
Bad {· · · } : endlich fehlerbehaftet, nichtdeterministisch
⊥ : nicht terminierend
3
Imprecise Error Semantics [Peyton Jones et al. 1999]
Grundidee:
Ok v : nicht fehlerbehaftet
Bad {· · · } : endlich fehlerbehaftet, nichtdeterministisch
⊥ : nicht terminierend
Definiertheits-Ordnung:
Bad
Ok
⊥
3
Imprecise Error Semantics [Peyton Jones et al. 1999]
Grundidee:
Ok v : nicht fehlerbehaftet
Bad {· · · } : endlich fehlerbehaftet, nichtdeterministisch
⊥ : nicht terminierend
Definiertheits-Ordnung:
Bad e2
Bad e1
e2 ⊆ e1
Bad
Ok
⊥
3
Imprecise Error Semantics [Peyton Jones et al. 1999]
Fortpflanzung von Fehlern:
• (error s1 ) + (error s2 )
Bad {s1 , s2 }
4
Imprecise Error Semantics [Peyton Jones et al. 1999]
Fortpflanzung von Fehlern:
• (error s1 ) + (error s2 )
• 3 + (error s)
Bad {s1 , s2 }
Bad {s}
4
Imprecise Error Semantics [Peyton Jones et al. 1999]
Fortpflanzung von Fehlern:
• (error s1 ) + (error s2 )
• 3 + (error s)
• loop + (error s)
Bad {s1 , s2 }
Bad {s}
⊥
4
Imprecise Error Semantics [Peyton Jones et al. 1999]
Fortpflanzung von Fehlern:
• (error s1 ) + (error s2 )
• 3 + (error s)
Bad {s1 , s2 }
Bad {s}
• loop + (error s)
• (error s1 ) (error s2 )
⊥
Bad {s1 , s2 }
4
Imprecise Error Semantics [Peyton Jones et al. 1999]
Fortpflanzung von Fehlern:
• (error s1 ) + (error s2 )
• 3 + (error s)
Bad {s1 , s2 }
Bad {s}
• loop + (error s)
• (error s1 ) (error s2 )
• (λx → 3) (error s)
⊥
Bad {s1 , s2 }
Ok 3
4
Imprecise Error Semantics [Peyton Jones et al. 1999]
Fortpflanzung von Fehlern:
• (error s1 ) + (error s2 )
• 3 + (error s)
Bad {s1 , s2 }
Bad {s}
• loop + (error s)
• (error s1 ) (error s2 )
• (λx → 3) (error s)
⊥
Bad {s1 , s2 }
Ok 3
• case (error s1 ) of {(x, y ) → error s2 }
Bad {s1 , s2 }
4
Auswirkungen auf Programmäquivalenz
„Normalerweise“:
takeWhile p (map h l ) = map h (takeWhile (p ◦ h) l )
wobei:
takeWhile :: (α → Bool) → [α] → [α]
takeWhile p [ ]
= []
takeWhile p (a : as) | p a
= a : takeWhile p as
| otherwise = [ ]
map :: (α → β) → [α] → [β]
map h [ ]
= []
map h (a : as) = h a : map h as
5
Auswirkungen auf Programmäquivalenz
„Normalerweise“:
takeWhile p (map h l ) = map h (takeWhile (p ◦ h) l )
wobei:
takeWhile :: (α → Bool) → [α] → [α]
takeWhile p [ ]
= []
takeWhile p (a : as) | p a
= a : takeWhile p as
| otherwise = [ ]
map :: (α → β) → [α] → [β]
map h [ ]
= []
map h (a : as) = h a : map h as
Aber nun:
takeWhile null (map tail (error s))
6=
map tail (takeWhile (null ◦ tail) (error s))
5
Auswirkungen auf Programmäquivalenz
„Normalerweise“:
takeWhile p (map h l ) = map h (takeWhile (p ◦ h) l )
wobei:
takeWhile :: (α → Bool) → [α] → [α]
takeWhile p [ ]
= []
takeWhile p (a : as) | p a
= a : takeWhile p as
| otherwise = [ ]
map :: (α → β) → [α] → [β]
map h [ ]
= []
map h (a : as) = h a : map h as
Aber nun:
takeWhile null (map tail (error s))
6=
map tail (takeWhile (null ◦ tail) (error s))
s
s oder “empty list”
5
Auswirkungen auf Programmäquivalenz
Denn:
takeWhile (null ◦ tail) (error s)
Bad {s, “empty list”}
wobei:
takeWhile p [ ]
= []
takeWhile p (a : as) | p a
= a : (takeWhile p as)
| otherwise = [ ]
tail [ ]
= error “empty list”
tail (a : as) = as
null [ ]
= True
null (a : as) = False
6
Auswirkungen auf Programmäquivalenz
Denn:
takeWhile (null ◦ tail) (error s)
Bad {s, “empty list”}
wobei:
takeWhile p [ ]
= []
takeWhile p (a : as) | p a
= a : (takeWhile p as)
| otherwise = [ ]
tail [ ]
= error “empty list”
tail (a : as) = as
null [ ]
= True
null (a : as) = False
6
Auswirkungen auf Programmäquivalenz
Denn:
takeWhile (null ◦ tail) (error s)
Bad {s, “empty list”}
wobei:
takeWhile p [ ]
= []
takeWhile p (a : as) | p a
= a : (takeWhile p as)
| otherwise = [ ]
tail [ ]
= error “empty list”
tail (a : as) = as
null [ ]
= True
null (a : as) = False
6
Auswirkungen auf Programmäquivalenz
Denn:
takeWhile (null ◦ tail) (error s)
Bad {s, “empty list”}
wobei:
takeWhile p [ ]
= []
takeWhile p (a : as) | p a
= a : (takeWhile p as)
| otherwise = [ ]
tail [ ]
= error “empty list”
tail (a : as) = as
null [ ]
= True
null (a : as) = False
6
Auswirkungen auf Programmäquivalenz
Denn:
takeWhile (null ◦ tail) (error s)
Bad {s, “empty list”}
wobei:
takeWhile p [ ]
= []
takeWhile p (a : as) | p a
= a : (takeWhile p as)
| otherwise = [ ]
tail [ ]
= error “empty list”
tail (a : as) = as
null [ ]
= True
null (a : as) = False
6
Auswirkungen auf Programmäquivalenz
Denn:
takeWhile (null ◦ tail) (error s)
Bad {s, “empty list”}
wobei:
takeWhile p [ ]
= []
takeWhile p (a : as) | p a
= a : (takeWhile p as)
| otherwise = [ ]
tail [ ]
= error “empty list”
tail (a : as) = as
null [ ]
= True
null (a : as) = False
6
Auswirkungen auf Programmäquivalenz
Denn:
takeWhile (null ◦ tail) (error s)
Bad {s, “empty list”}
wobei:
takeWhile p [ ]
= []
takeWhile p (a : as) | p a
= a : (takeWhile p as)
| otherwise = [ ]
tail [ ]
= error “empty list”
tail (a : as) = as
null [ ]
= True
null (a : as) = False
6
Auswirkungen auf Programmäquivalenz
Denn:
takeWhile (null ◦ tail) (error s)
während:
Bad {s, “empty list”}
takeWhile null (map tail (error s))
wobei:
Bad {s}
takeWhile p [ ]
= []
takeWhile p (a : as) | p a
= a : (takeWhile p as)
| otherwise = [ ]
map h [ ]
= []
map h (a : as) = (h a) : (map h as)
null [ ]
= True
null (a : as) = False
6
Auswirkungen auf Programmäquivalenz
Denn:
takeWhile (null ◦ tail) (error s)
während:
Bad {s, “empty list”}
takeWhile null (map tail (error s))
wobei:
Bad {s}
takeWhile p [ ]
= []
takeWhile p (a : as) | p a
= a : (takeWhile p as)
| otherwise = [ ]
map h [ ]
= []
map h (a : as) = (h a) : (map h as)
null [ ]
= True
null (a : as) = False
6
Auswirkungen auf Programmäquivalenz
Denn:
takeWhile (null ◦ tail) (error s)
während:
Bad {s, “empty list”}
takeWhile null (map tail (error s))
wobei:
Bad {s}
takeWhile p [ ]
= []
takeWhile p (a : as) | p a
= a : (takeWhile p as)
| otherwise = [ ]
map h [ ]
= []
map h (a : as) = (h a) : (map h as)
null [ ]
= True
null (a : as) = False
6
Auswirkungen auf Programmäquivalenz
Denn:
takeWhile (null ◦ tail) (error s)
während:
Bad {s, “empty list”}
takeWhile null (map tail (error s))
wobei:
Bad {s}
takeWhile p [ ]
= []
takeWhile p (a : as) | p a
= a : (takeWhile p as)
| otherwise = [ ]
map h [ ]
= []
map h (a : as) = (h a) : (map h as)
null [ ]
= True
null (a : as) = False
6
Auswirkungen auf Programmäquivalenz
Denn:
takeWhile (null ◦ tail) (error s)
während:
Bad {s, “empty list”}
takeWhile null (map tail (error s))
wobei:
Bad {s}
takeWhile p [ ]
= []
takeWhile p (a : as) | p a
= a : (takeWhile p as)
| otherwise = [ ]
map h [ ]
= []
map h (a : as) = (h a) : (map h as)
null [ ]
= True
null (a : as) = False
6
Auswirkungen auf Programmäquivalenz
Denn:
takeWhile (null ◦ tail) (error s)
während:
Bad {s, “empty list”}
takeWhile null (map tail (error s))
wobei:
Bad {s}
takeWhile p [ ]
= []
takeWhile p (a : as) | p a
= a : (takeWhile p as)
| otherwise = [ ]
map h [ ]
= []
map h (a : as) = (h a) : (map h as)
null [ ]
= True
null (a : as) = False
6
Auswirkungen auf Programmäquivalenz
Denn:
takeWhile (null ◦ tail) (error s)
während:
Bad {s, “empty list”}
takeWhile null (map tail (error s))
Bad {s}
Also:
takeWhile null (map tail (error s))
6=
map tail (takeWhile (null ◦ tail) (error s))
6
Auswirkungen auf Programmäquivalenz
Denn:
takeWhile (null ◦ tail) (error s)
während:
Bad {s, “empty list”}
takeWhile null (map tail (error s))
Bad {s}
Also:
takeWhile null (map tail (error s))
6=
map tail (takeWhile (null ◦ tail) (error s))
Man stelle sich dies in folgendem Kontext vor:
catchJust errorCalls (evaluate · · ·)
(λs → if s == “empty list”
then return [[42]]
else return [ ])
6
Freies Theorem
Bisheriger Kenntnisstand:
g p (map h l ) = map h (g (p ◦ h) l )
für jedes g :: (α → Bool) → [α] → [α], wenn
• p 6= ⊥,
• h strikt (h ⊥ = ⊥) und
• h total (∀x 6= ⊥. h x 6= ⊥).
7
Freies Theorem
Bisheriger Kenntnisstand:
g p (map h l ) = map h (g (p ◦ h) l )
für jedes g :: (α → Bool) → [α] → [α], wenn
• p 6= ⊥,
• h strikt (h ⊥ = ⊥) und
• h total (∀x 6= ⊥. h x 6= ⊥).
Was sind entsprechende Bedingungen „in echt“?
Bad
Ok
⊥
7
Schweiß und Tränen . . .
. . . durchgängige Formalisierung der Semantik
8
Schweiß und Tränen . . .
. . . durchgängige Formalisierung der Semantik
. . . Einstieg in Beweis des Parametrizitäts-Theorems
8
Schweiß und Tränen . . .
. . . durchgängige Formalisierung der Semantik
. . . Einstieg in Beweis des Parametrizitäts-Theorems
. . . Betrachtung der interessanten Induktionsfälle
8
Schweiß und Tränen . . .
. . . durchgängige Formalisierung der Semantik
. . . Einstieg in Beweis des Parametrizitäts-Theorems
. . . Betrachtung der interessanten Induktionsfälle
. . . Identifizierung geeigneter Bedingungen auf Relationsebene
8
Schweiß und Tränen . . .
. . . durchgängige Formalisierung der Semantik
. . . Einstieg in Beweis des Parametrizitäts-Theorems
. . . Betrachtung der interessanten Induktionsfälle
. . . Identifizierung geeigneter Bedingungen auf Relationsebene
. . . Anpassung relationaler Aktionen
8
Schweiß und Tränen . . .
. . . durchgängige Formalisierung der Semantik
. . . Einstieg in Beweis des Parametrizitäts-Theorems
. . . Betrachtung der interessanten Induktionsfälle
. . . Identifizierung geeigneter Bedingungen auf Relationsebene
. . . Anpassung relationaler Aktionen
. . . Vervollständigung allgemeiner Beweis
8
Schweiß und Tränen . . .
. . . durchgängige Formalisierung der Semantik
. . . Einstieg in Beweis des Parametrizitäts-Theorems
. . . Betrachtung der interessanten Induktionsfälle
. . . Identifizierung geeigneter Bedingungen auf Relationsebene
. . . Anpassung relationaler Aktionen
. . . Vervollständigung allgemeiner Beweis
. . . Übertragung der Bedingungen auf Funktionsebene
8
Schweiß und Tränen . . .
. . . durchgängige Formalisierung der Semantik
. . . Einstieg in Beweis des Parametrizitäts-Theorems
. . . Betrachtung der interessanten Induktionsfälle
. . . Identifizierung geeigneter Bedingungen auf Relationsebene
. . . Anpassung relationaler Aktionen
. . . Vervollständigung allgemeiner Beweis
. . . Übertragung der Bedingungen auf Funktionsebene
. . . Anwendung auf konkrete Funktionen
8
. . . Anwendung auf „takeWhile“
Für jedes g :: (α → Bool) → [α] → [α],
g p (map h l ) = map h (g (p ◦ h) l )
9
. . . Anwendung auf „takeWhile“
Für jedes g :: (α → Bool) → [α] → [α],
g p (map h l ) = map h (g (p ◦ h) l )
vorausgesetzt
• p und h nicht fehlerbehaftet,
h
p
Bad
Ok
⊥
9
. . . Anwendung auf „takeWhile“
Für jedes g :: (α → Bool) → [α] → [α],
g p (map h l ) = map h (g (p ◦ h) l )
vorausgesetzt
• p und h nicht fehlerbehaftet,
• h ⊥ = ⊥,
h
p
Bad
Ok
⊥
h
9
. . . Anwendung auf „takeWhile“
Für jedes g :: (α → Bool) → [α] → [α],
g p (map h l ) = map h (g (p ◦ h) l )
vorausgesetzt
• p und h nicht fehlerbehaftet,
• h ⊥ = ⊥,
• h verhält sich als Identität auf endlichen Fehlern, und
h
h
h
p
h
Bad
Ok
⊥
h
9
. . . Anwendung auf „takeWhile“
Für jedes g :: (α → Bool) → [α] → [α],
g p (map h l ) = map h (g (p ◦ h) l )
vorausgesetzt
• p und h nicht fehlerbehaftet,
• h ⊥ = ⊥,
• h verhält sich als Identität auf endlichen Fehlern, und
• h bildet Nichtfehler auf Nichtfehler ab.
h
h
h
h
p
h
Bad
Ok
⊥
h
9
Herunterladen