Programmieren in Haskell

Werbung
Programmieren in Haskell
Programmiermethodik
Programmieren in Haskell
1
Was wir heute machen
• Spezifikation
• Strukturelle Rekursion
• Strukturelle Induktion
Programmieren in Haskell
2
Spezifikation
sort [8, 3, 5, 3, 6, 1]
⇒
[1, 3, 3, 5, 6, 8]
sort "hello world"
⇒
" dehllloorw"
sort ["Bein", "Anfall", "Anna"]
⇒
["Anfall", "Anna", "Bein"]
sort [(1, 7), (1, 3), (2, 2)]
⇒
[(1, 3), (1, 7), (2, 2)]
Programmieren in Haskell
3
sort :: (Ord a) => [a] -> OrdList a
Programmieren in Haskell
4
sort :: (Ord a) => [a] -> OrdList a
ordered
ordered
ordered
ordered
:: (Ord a)
[]
[a]
(a1:a2:as)
Programmieren in Haskell
=> [a] -> Bool
= True
= True
= a1 <= a2 && ordered (a2:as)
4
sort :: (Ord a) => [a] -> OrdList a
ordered
ordered
ordered
ordered
:: (Ord a)
[]
[a]
(a1:a2:as)
=> [a] -> Bool
= True
= True
= a1 <= a2 && ordered (a2:as)
Spezifikation 1: Für alle Listen x :: [τ ] muß gelten:
ordered (sort x)
Programmieren in Haskell
=
True .
(1)
4
sort :: (Ord a) => [a] -> OrdList a
ordered
ordered
ordered
ordered
:: (Ord a)
[]
[a]
(a1:a2:as)
=> [a] -> Bool
= True
= True
= a1 <= a2 && ordered (a2:as)
Spezifikation 1: Für alle Listen x :: [τ ] muß gelten:
ordered (sort x)
=
True .
(1)
Reicht das?
Programmieren in Haskell
4
sort :: (Ord a) => [a] -> OrdList a
ordered
ordered
ordered
ordered
:: (Ord a)
[]
[a]
(a1:a2:as)
=> [a] -> Bool
= True
= True
= a1 <= a2 && ordered (a2:as)
Spezifikation 1: Für alle Listen x :: [τ ] muß gelten:
ordered (sort x)
=
True .
(1)
Reicht das? Nein: \x -> []
Programmieren in Haskell
4
Multimengen
∅ die leere Multimenge,
*a+ die einelementige Multimenge, die genau ein Vorkommen von a enthält,
x ] y die Vereinigung der Elemente von x und y; das „+“ im Vereinigungszeichen
deutet an, daß sich die Vorkommen in x und y akkumulieren.
Programmieren in Haskell
∅]x
=
x
(2)
x]∅
=
x
(3)
x]y
=
y]x
(4)
(x ] y) ] z
=
x ] (y ] z)
(5)
5
bag :: [a] -> Bag a
bag []
= ∅
bag (a:as) = *a+ ] bag as
Spezifikation 2: Für alle Listen x :: [τ ] muß gelten:
ordered (sort x) = True ∧ bag (sort x) = bag x .
Programmieren in Haskell
(6)
6
Strukturelle Rekursion auf Listen
length :: [a] -> Int
length []
= 0
length (a:as) = 1 + length as
Programmieren in Haskell
-- vordefiniert
7
Rekursionsbasis: []
Rekursionsschritt: (a:as)
Schema der strukturellen Rekursion auf Listen:
f
f []
f (a : as)
where s
Programmieren in Haskell
::
=
=
=
[σ] -> τ
e1
e2
f as
8
Sortieren durch Einfügen
insertionSort
insertionSort []
insertionSort (a : as)
where s
Programmieren in Haskell
::
=
=
=
(Ord a) => [a] -> OrdList a
e1
e2
insertionSort as
9
Sortieren durch Einfügen
insertionSort
insertionSort []
insertionSort (a : as)
where s
::
=
=
=
(Ord a) => [a] -> OrdList a
e1
e2
insertionSort as
insertionSort :: (Ord a) => [a] -> OrdList a
insertionSort []
= []
insertionSort (a:as) = insert a (insertionSort as)
Programmieren in Haskell
9
Erweitertes Rekursionsschema:
g
g i []
g i (a : as)
where s
insert
insert a []
insert a (a’ : as)
where s
Programmieren in Haskell
::
=
=
=
::
=
=
=
σ1 -> [σ2 ] -> τ
e1
e2
g e3 as
(Ord a) => a -> OrdList a -> OrdList a
e1
e2
insert e3 as
10
insert a []
insert a (a’ : as)
| a <= a’
| otherwise
where s
=
[a]
=
=
=
e21
e22
insert e3 as
insert :: (Ord a) => a -> [a] -> [a]
insert a []
= [a]
insert a (a’:as)
| a <= a’
= a:a’:as
| otherwise = a’:insert a as
Programmieren in Haskell
11
isort (8 : 3 : 5 : 3 : 6 : 1 : [])
⇒
ins 8 (isort (3 : 5 : 3 : 6 : 1 : []))
(Def. isort)
⇒
ins 8 (ins 3 (isort (5 : 3 : 6 : 1 : [])))
(Def. isort)
⇒
...
⇒
ins 8 (ins 3 (ins 5 (ins 3 (ins 6 (ins 1 [])))))
⇒
ins 8 (ins 3 (ins 5 (ins 3 (ins 6 (1 : [])))))
(Def. ins)
⇒
ins 8 (ins 3 (ins 5 (ins 3 (1 : ins 6 []))))
(Def. ins)
⇒
ins 8 (ins 3 (ins 5 (1 : ins 3 (ins 6 []))))
(Def. ins)
⇒
...
⇒
1 : ins 8 (ins 3 (ins 5 (ins 3 (ins 6 []))))
Programmieren in Haskell
(Def. isort)
(Def. ins)
12
Strukturelle Rekursion auf Bäumen
data Tree a = Nil
| Leaf a
| Br (Tree a) (Tree a)
deriving Show
Rekursionsbasis (Nil) Das Problem wird für den leeren Baum gelöst.
Rekursionsbasis (Leaf a) Das Problem wird für das Blatt Leaf a gelöst.
Rekursionsschritt (Br l r) Um das Problem für den Baum Br l r zu lösen,
werden rekursiv Lösungen für l und r bestimmt, die zu einer Lösung für
Br l r erweitert werden.
Programmieren in Haskell
13
Schema der strukturellen Rekursion of Bäumen:
f
f Nil
f (Leaf a)
f (Br l r)
where sl
sr
Programmieren in Haskell
::
=
=
=
=
=
Tree σ -> τ
e1
e2
e3
f l
f r
14
size
size
size
size
:: Tree a -> Integer
Nil
= 1
(Leaf _) = 1
(Br l r) = size l + size r
depth
depth
depth
depth
:: Tree a -> Integer
Nil
= 0
(Leaf _) = 0
(Br l r) = max (depth l) (depth r) + 1
Programmieren in Haskell
15
Das allgemeine Rekursionsschema
data T a1 . . . am
=
C1 t11 . . . t1n1
|
...
|
Cr tr1 . . . trnr
Seien li1 ,. . . , lipi mit 1 6 li1 < li2 < · · · < lipi 6 ni die Positionen, an denen der
Konstruktor Ci rekursiv ist
Programmieren in Haskell
16
Allgemeines Schema der strukturellen Rekursion:
f
f (C1 x11 . . . x1n1 )
where s11
...
s1p1
...
f (Cr xr1 . . . xrnr )
where sr1
...
srpr
Programmieren in Haskell
::
=
=
T σ1 . . . σm -> τ
e1
f x1l11
=
f x1l1p1
=
=
er
f xrlr1
=
f xrlrpr
17
Verstärkung der Rekursion
reverse’’ :: [a] -> [a]
-- vordefiniert
reverse’’ []
= []
reverse’’ (a:as) = reverse’’ as ++ [a]
Programmieren in Haskell
18
Verstärkung der Rekursion
reverse’’ :: [a] -> [a]
-- vordefiniert
reverse’’ []
= []
reverse’’ (a:as) = reverse’’ as ++ [a]
Spezifikation:
reel
reel x y
Programmieren in Haskell
::
=
[a] -> [a] -> [a]
reverse x ++ y
18
Rekursionsbasis (x = []):
reel [] y
Programmieren in Haskell
=
reverse [] ++ y
(Spezifikation)
=
[] ++ y
(Def. reverse)
=
y
(Def. (++))
19
Rekursionsschritt (x = a:as):
reel (a:as) y
Programmieren in Haskell
=
reverse (a:as) ++ y
(Spezifikation)
=
(reverse as ++ [a]) ++ y
(Def. reverse)
=
reverse as ++ ([a] ++ y)
(Ass. (++))
=
reverse as ++ (a:y)
(Def. (++))
=
reel as (a:y)
(Spezifikation)
20
reel :: [a] -> [a] -> [a]
reel []
y = y
reel (a:as) y = reel as (a:y)
Programmieren in Haskell
21
reel :: [a] -> [a] -> [a]
reel []
y = y
reel (a:as) y = reel as (a:y)
reverse xs
Programmieren in Haskell
=
reverse xs ++ []
=
(reel xs [])
(Def. (++))
(Spezifikation)
21
reel :: [a] -> [a] -> [a]
reel []
y = y
reel (a:as) y = reel as (a:y)
reverse xs
=
reverse xs ++ []
=
(reel xs [])
(Def. (++))
(Spezifikation)
reverse’’’ :: [a] -> [a]
reverse’’’ as = reel as []
Programmieren in Haskell
21
Strukturelle Induktion auf Listen
Induktionsbasis ([]): Wir zeigen die Aussage zunächst für die leere Liste [].
Induktionsschritt (a:as): Wir nehmen an, daß die Aussage für die Liste as gilt, und
zeigen, daß sie unter dieser Voraussetzung auch für a:as gilt.
Beweisregel:
Φ([])
(∀a, as) Φ(as) =⇒ Φ(a:as)
(∀x) Φ(x)
Programmieren in Haskell
22
Spezifikation von insert:
Programmieren in Haskell
ordered x = True =⇒ ordered (insert a x) = True
(7)
bag (insert a x) = *a+ ] bag x
(8)
23
Φ(x)
⇐⇒
(∀a) bag (insert a x) = *a+ ] bag x
(9)
Induktionsbasis (x = []):
bag (insert a [])
Programmieren in Haskell
=
bag [a]
=
*a+ ] bag []
(Def. insert)
(Def. bag)
24
⇐⇒
Φ(x)
(∀a) bag (insert a x) = *a+ ] bag x
Induktionsschritt (x = a’:as):
Fall a <= a’ = True:
bag (insert a (a’:as))
Programmieren in Haskell
=
bag (a:a’:as)
=
*a+ ] bag (a’:as)
(Def. insert)
(Def. bag)
25
⇐⇒
Φ(x)
(∀a) bag (insert a x) = *a+ ] bag x
Induktionsschritt (x = a’:as):
Fall a <= a’ = False:
bag (insert a (a’:as))
=
bag (a’:insert a as)
=
*a’+ ] bag (insert a as)
=
=
=
Programmieren in Haskell
*a’+ ] (*a+ ] bag as)
*a+ ] (*a’+ ] bag as)
*a+ ] bag (a’:as)
(Def. insert)
(Def. bag)
(I.V.)
(Ass., Komm. ])
(Def. bag)
26
Φ(x)
⇐⇒
(∀a) ordered x = True =⇒ ordered (insert a x) = True
Induktionsbasis (x = []):
ordered (insert a [])
Programmieren in Haskell
=
ordered [a]
(Def. insert)
=
True
(Def. ordered)
27
Induktionsschritt (x = a’:as):
1. x = a1 :as ∧ a<=a1 = True
2. x = a1 :as ∧ a<=a1 = False ∧ as = []
3. x = a1 :as ∧ a<=a1 = False ∧ as = a2 :as0
Programmieren in Haskell
28
Φ(x)
⇐⇒
(∀a) ordered x = True =⇒ ordered (insert a x) = True
Teilfall a<=a2 = True:
ordered (insert a (a1 :as))
Programmieren in Haskell
=
ordered (a1 :insert a as)
(Def. insert)
=
ordered (a1 :a:as)
(Def. insert)
=
a1 <=a && a<=a2 && ordered as
(Def. ordered)
=
True
(Vor.)
29
⇐⇒
Φ(x)
(∀a) ordered x = True =⇒ ordered (insert a x) = True
Teilfall a<=a2 = False:
ordered (insert a (a1 :as))
=
ordered (a1 :insert a as)
(Def. insert)
=
ordered (a1 :a2 :insert a as0 )
(Def. insert)
=
a1 <=a2 && ordered (a2 :insert a as0 )
(Def. ordered)
=
ordered (a2 :insert a as0 )
=
ordered (insert a as)
(Def. insert)
=
True
(Vor. und I.V.)
Programmieren in Haskell
(Vor. undDef. (&&))
30
Strukturelle Induktion auf Bäumen
Induktionsbasis (Nil): Wir zeigen die Aussage für den leeren Baum Nil.
Induktionsbasis (Leaf a): Wir zeigen die Aussage für das Blatt Leaf a.
Induktionsschritt (Br l r): Wir nehmen an, daß die Aussage für den Teilbaum l und für
den Teilbaum r gilt, und zeigen, daß sie unter dieser Voraussetzung auch für den Baum
Br l r gilt.
Programmieren in Haskell
31
Strukturelle Induktion auf Bäumen
Induktionsbasis (Nil): Wir zeigen die Aussage für den leeren Baum Nil.
Induktionsbasis (Leaf a): Wir zeigen die Aussage für das Blatt Leaf a.
Induktionsschritt (Br l r): Wir nehmen an, daß die Aussage für den Teilbaum l und für
den Teilbaum r gilt, und zeigen, daß sie unter dieser Voraussetzung auch für den Baum
Br l r gilt.
Φ(Nil)
(∀a) Φ(Leaf a)
(∀l, r) Φ(l) ∧ Φ(r) =⇒ Φ(Br l r)
(∀t) Φ(t)
Programmieren in Haskell
31
Φ(t)
Programmieren in Haskell
⇐⇒
size t 6 2^depth t
32
Φ(t)
⇐⇒
size t 6 2^depth t
Induktionsbasis (t = Nil):
size Nil
=
1
(Def. size)
=
2^0
(Def. (^))
=
2^depth Nil
Programmieren in Haskell
(Def. depth)
32
Φ(t)
⇐⇒
Induktionsbasis (t = Nil):
size t 6 2^depth t
Induktionsbasis (t = Leaf a):
size Nil
size (Leaf a)
=
1
(Def. size)
=
1
(Def. size)
=
2^0
(Def. (^))
=
2^0
(Def. (^))
=
2^depth Nil
(Def. depth)
=
2^depth (Leaf a)
Programmieren in Haskell
(Def. depth)
32
⇐⇒
Φ(t)
size t 6 2^depth t
Induktionsschritt (t = Br l r):
size (Br l r)
Programmieren in Haskell
=
size l + size r
(Def. size)
6
2^depth l + 2^depth r
6
2 * 2^(max (depth l) (depth r))
(Eig. max)
=
2^(max (depth l) (depth r) + 1)
(Eig. (^))
=
2^depth (Br l r)
(I.V.)
(Def. depth)
33
Das allgemeine Induktionsschema
data T a1 . . . am = C1 t11 . . . t1n1 | . . . |Cr tr1 . . . trnr
Programmieren in Haskell
34
Das allgemeine Induktionsschema
data T a1 . . . am = C1 t11 . . . t1n1 | . . . |Cr tr1 . . . trnr
Seien li1 ,. . . , lipi mit 1 6 li1 < li2 < · · · < lipi 6 ni die Positionen, an denen der
Konstruktor Ci rekursiv ist
Programmieren in Haskell
34
Das allgemeine Induktionsschema
data T a1 . . . am = C1 t11 . . . t1n1 | . . . |Cr tr1 . . . trnr
Seien li1 ,. . . , lipi mit 1 6 li1 < li2 < · · · < lipi 6 ni die Positionen, an denen der
Konstruktor Ci rekursiv ist
(∀x11 . . . x1n1 ) Φ(x1l11 ) ∧ · · · ∧ Φ(x1l1p1 ) =⇒ Φ(C1 x11 . . . x1n1 )
...
(∀xr1 . . . xrnr ) Φ(xrlr1 ) ∧ · · · ∧ Φ(xrlrpr ) =⇒ Φ(Cr xr1 . . . xrnr )
(∀x) Φ(x)
Programmieren in Haskell
34
Spezialfall: Natürliche Induktion
data Natural = Zero | Succ Natural
Φ(Zero)
(∀n) Φ(n) =⇒ Φ(Succ n)
(∀n ∈ Nat) Φ(n)
Programmieren in Haskell
35
Herunterladen