Kapitel 6: Abstraktion

Werbung
Kapitel 6: Abstraktion
Programmieren in Haskell
1
Nachtrag Listenbeschreibungen
divisors’ :: (Integral a) => a -> [a]
divisors’ n = [d | d <- [1..n], n ‘mod‘ d == 0]
primes’ :: (Integral a) => [a]
primes’ = [n | n <- [2..], divisors’ n == [1,n]]
Programmieren in Haskell
2
Nachtrag Listenbeschreibungen
divisors’ :: (Integral a) => a -> [a]
divisors’ n = [d | d <- [1..n], n ‘mod‘ d == 0]
primes’ :: (Integral a) => [a]
primes’ = [n | n <- [2..], divisors’ n == [1,n]]
sieve :: (Integral a) => [a] -> [a]
sieve (a:x) = a:sieve [n | n <- x, n ‘mod‘ a /= 0]
primes’’ :: (Integral a) => [a]
primes’’ = sieve [2..]
Programmieren in Haskell
2
Noch ein winziger Nachtrag
concat’ xs = [a | x <- xs, a <- x]
Programmieren in Haskell
3
8-Damen-Problem
4
Q
3
Q
[2,4,1,3]
2 Q
1
Q
1
2
3
4
Repräsentation: Liste der Zeilenpositionen, von links nach rechts
Programmieren in Haskell
4
Diagonalen, aufsteigend und absteigend
Programmieren in Haskell
4 −3 −2 −1 0
4 5 6 7 8
3 −2 −1
0
1
3 4 5 6 7
2 −1
0
1
2
2 3 4 5 6
1
0
1
2
3
1 2 3 4 5
1
2
3
4
1 2
3
4
5
Diagonalen, aufsteigend und absteigend
4 −3 −2 −1 0
4 5 6 7 8
3 −2 −1
0
1
3 4 5 6 7
2 −1
0
1
2
2 3 4 5 6
1
0
1
2
3
1 2 3 4 5
1
2
3
4
1 2
3
4
Die Nummer der aufsteigenden Diagonale ergibt sich als Differenz von Spalten- und
Reihenposition, die Nummer der absteigenden Diagonale entsprechend durch die
Summe.
Programmieren in Haskell
5
• aufsteigend: gleiche Diagonale durch: j → j + 1, i → i + 1
dann: d → (j + 1) − (i + 1) = j − i
oder: j → j − 1, i → i − 1
dann: d → (j − 1) − (i − 1) = j − i
Programmieren in Haskell
6
• aufsteigend: gleiche Diagonale durch: j → j + 1, i → i + 1
dann: d → (j + 1) − (i + 1) = j − i
oder: j → j − 1, i → i − 1
dann: d → (j − 1) − (i − 1) = j − i
• absteigend: gleiche Diagonale durch: j → j + 1, i → i − 1
dann: d → (j + 1) + (i − 1) = j + i
oder: j → j − 1, i → i + 1
dann: d → (j − 1) − (i + 1) = j + i
Programmieren in Haskell
6
type Board = [Integer]
queens :: Integer -> [Board]
queens n = place 1 [1..n] [] []
Die Hilfsfunktion place erhält vier Argumente: die Nummer der aktuellen Spalte,
die Liste der noch nicht verwendeten Reihenpositionen und die Nummern der
bereits belegten auf- und absteigenden Diagonalen.
Programmieren in Haskell
7
place :: Integer -> [Integer] -> [Integer] -> [Integer] -> [Board]
place c [] ud dd = [[]]
place c rs ud dd = [q:qs | q <- rs,
let uq = q - c,
let dq = q + c,
uq ‘notElem‘ ud,
dq ‘notElem‘ dd,
qs <- place (c+1) (delete q rs) (uq:ud) (dq:dd)]
delete q (x:xs) | q == x
= xs
| otherwise = x:delete q xs
Programmieren in Haskell
8
Semantik von Listenbeschreibungen
Programmieren in Haskell
[ e | p <- l ]
=
map (\p -> e) l
[ e | b ]
=
if b then [e] else []
[ e | let ds ]
=
let ds in [e]
[ e | q1 , q2 ]
=
concat [ [ e | q2 ] | q1 ]
9
Funktionen als Parameter
data Person
= Person Sex FirstName LastName Date
deriving (Eq,Ord,Show)
data Date
= Date Int Int Int deriving (Eq,Ord,Show)
data Sex
= Female | Male
deriving (Eq,Ord,Show)
type FirstName = String
type LastName = String
Programmieren in Haskell
10
Funktionen als Parameter
data Person
= Person Sex FirstName LastName Date
deriving (Eq,Ord,Show)
data Date
= Date Int Int Int deriving (Eq,Ord,Show)
data Sex
= Female | Male
deriving (Eq,Ord,Show)
type FirstName = String
type LastName = String
Da lexikographisch verglichen wird, werden Elemente vom Typ Person zuerst nach
dem Geschlecht, dann nach dem Vornamen, dem Nachnamen und dem
Geburtsdatum angeordnet.
Programmieren in Haskell
10
Verallgemeinerung von isort
isortBy :: (a -> a -> Bool) -> [a] -> [a]
isortBy (<=) = isort
where
isort []
= []
isort (a:x)
= insert a (isort x)
insert a []
= [a]
insert a x@(b:y)
| a <= b
= a:x
| otherwise = b:insert a y
Programmieren in Haskell
11
sortByLastName = isortBy (\p q -> components p <= components q)
where components (Person s f l d) = (l,f,d)
sortByDateOfBirth = isortBy (\p q -> dateOfBirth p <= dateOfBirth q)
where dateOfBirth (Person _ _ _ d) = d
Programmieren in Haskell
12
Binäre Suche 2
binarySearch :: (Ord b, Integral a, Ix a) => Array a b -> b -> Bool
binarySearch a e = within (bounds a)
where within (l,r) = l <= r
&& let m = (l + r) ‘div‘ 2
in case compare e (a!m) of
LT -> within (l, m-1)
EQ -> True
GT -> within (m+1, r)
Programmieren in Haskell
13
binarySearchBy’ :: (Integral a) => (a -> Ordering) -> (a,a) -> Bool
binarySearchBy’ cmp = within
where within (l,r) = if l > r then False
else let m = (l+r) ‘div‘ 2
in case cmp m of
LT -> within (l, m-1)
EQ -> True
GT -> within (m+1, r)
Programmieren in Haskell
14
binarySearchBy :: (Integral a) => (a -> Ordering) -> (a,a) -> Maybe a
binarySearchBy cmp = within
where within (l,r) = if l > r then Nothing
else let m = (l+r) ‘div‘ 2
in case cmp m of
LT -> within (l, m-1)
EQ -> Just m
GT -> within (m+1, r)
Programmieren in Haskell
15
binarySearchBy :: (Integral a) => (a -> Ordering) -> (a,a) -> Maybe a
binarySearchBy cmp = within
where within (l,r) = if l > r then Nothing
else let m = (l+r) ‘div‘ 2
in case cmp m of
LT -> within (l, m-1)
EQ -> Just m
GT -> within (m+1, r)
binSearch a e = case r of Nothing -> False; Just _ -> True
where r = binarySearchBy (\i -> compare e (a!i)) (bounds a)
Programmieren in Haskell
15
Wörterbuch
englishGerman :: Array Int (String, String)
englishGerman = listArray (1,2) [("daffodil", "Narzisse"),
("dandelion","Loewenzahn")]
Programmieren in Haskell
16
Wörterbuch
englishGerman :: Array Int (String, String)
englishGerman = listArray (1,2) [("daffodil", "Narzisse"),
("dandelion","Loewenzahn")]
german :: [Char] -> Maybe [Char]
german x = case r of Nothing -> Nothing
Just m -> Just (snd (englishGerman!m))
where r = binarySearchBy (\i -> compare x (fst (englishGerman!i)))
(bounds englishGerman)
Programmieren in Haskell
16
Offene Suche
openbinSearchBy :: (Integral a) => (a -> Ordering) -> a -> Maybe a
openbinSearchBy cmp l = lessThan l
where lessThan r = case cmp r of
LT -> binarySearchBy cmp (l,r)
EQ -> Just r
GT -> lessThan (2*r)
Programmieren in Haskell
17
Rekursionsschemata
Strukturelle Rekursion auf Listen:
Rekursionsbasis ([]) Das Problem wird für die leere Liste [] gelöst.
Rekursionsschritt (a:x) Um das Problem für die Liste a:x zu lösen, wird nach dem
gleichen Verfahren, d.h. rekursiv, zunächst eine Lösung für x bestimmt, die
anschließend zu einer Lösung für a:x erweitert wird.
Programmieren in Haskell
18
Vom Kochrezept zum Programm
structuralRecursionOnLists :: solution
-> (a -> [a] -> solution -> solution)
-> [a] -> solution
structuralRecursionOnLists base extend = rec
where rec []
= base
rec (a:x) = extend a x (rec x)
Programmieren in Haskell
-- base
-- extend
19
Insertionsort mit sROL
isort’ :: (Ord a) => [a] -> [a]
isort’ = structuralRecursionOnLists
[]
(\a _ s -> insert’’ a s)
insert’’ :: (Ord a) => a -> [a] -> [a]
insert’’ a = structuralRecursionOnLists
[a]
(\b x s -> if a <= b then a:b:x else b:s)
Programmieren in Haskell
20
Permutationen
perms [2,6,7] == [[2,6,7],[6,2,7],[6,7,2],[2,7,6],[7,2,6],[7,6,2]]
perms
[6,7] == [[6,7],[7,6]]
Programmieren in Haskell
21
Permutationen
perms [2,6,7] == [[2,6,7],[6,2,7],[6,7,2],[2,7,6],[7,2,6],[7,6,2]]
perms
[6,7] == [[6,7],[7,6]]
perms :: [a] -> [[a]]
perms []
= [[]]
perms (a:x) = [z | y <- perms x, z <- insertions a y]
insertions :: a -> [a] -> [[a]]
insertions a []
= [[a]]
insertions a x@(b:y) = (a:x):[b:z | z <- insertions a y]
Programmieren in Haskell
21
Eine Variante der sort-Spezifikation
sort :: (Ord a) => [a] -> [a]
sort x = head [s | s <- perms x, ordered s]
Programmieren in Haskell
22
Divide and Conquer
Ist das Problem einfach, wird es mit ad-hoc Methoden gelöst. Anderenfalls
wird es in einfachere Teilprobleme aufgeteilt, diese werden nach dem
gleichen Prinzip gelöst und anschließend zu einer Gesamtlösung
zusammengefügt.
Programmieren in Haskell
23
Divide and Conquer
Ist das Problem einfach, wird es mit ad-hoc Methoden gelöst. Anderenfalls
wird es in einfachere Teilprobleme aufgeteilt, diese werden nach dem
gleichen Prinzip gelöst und anschließend zu einer Gesamtlösung
zusammengefügt.
divideAndConquer :: (problem -> Bool)
--> (problem -> solution)
--> (problem -> [problem])
--> ([solution] -> solution)
--> problem -> solution
divideAndConquer easy solve divide conquer = rec
where rec x = if easy x then solve x
else conquer [rec y | y
Programmieren in Haskell
easy
solve
divide
conquer
<- divide x]
23
Mergesort mit dAC
msort’’ :: (Ord a) => [a] -> [a]
msort’’ = divideAndConquer
(\x -> drop 1 x == [])
(\x -> x)
(\x -> let k = length x ‘div‘ 2 in [take k x, drop k x])
(\[s,t] -> merge s t)
Programmieren in Haskell
24
Quicksort mit dAC
qsort :: (Ord a) => [a] -> [a]
qsort = divideAndConquer
(\x -> drop 1 x == [])
(\x -> x)
(\(a:x) -> [[ b | b <- x, b < a],[a],[b | b <- x, b >= a]])
(\[x,y,z] -> x++y++z)
Programmieren in Haskell
25
foldr und Kolleginnen
sum’’ :: (Num a) => [a] -> a
sum’’ []
= 0
sum’’ (a:x) = a + sum’’ x
or’’ :: [Bool] -> Bool
or’’ []
= False
or’’ (a:x) = a || or’’ x
Programmieren in Haskell
26
foldr und Kolleginnen
sum’’ :: (Num a) => [a] -> a
sum’’ []
= 0
sum’’ (a:x) = a + sum’’ x
or’’ :: [Bool] -> Bool
or’’ []
= False
or’’ (a:x) = a || or’’ x
foldr’ :: (a -> solution -> solution) -> solution -> [a] -> solution
foldr’ (*) e = f
where f []
= e
f (a:x) = a * f x
Programmieren in Haskell
26
sum’
product’
and’
or’
=
=
=
=
foldr
foldr
foldr
foldr
(+) 0
(*) 1
(&&) True
(||) False
(:) -> (*)
[] -> e
a1 :(a2 :· · ·:(an−1 :(an :[]))· · ·) -> a1 *(a2 *· · ·:(an−1 *(an :e))· · ·)
Programmieren in Haskell
27
Noch ein paar Beispiele
isort
length
x ++ y
reverse
concat
=
=
=
=
=
Programmieren in Haskell
foldr
foldr
foldr
foldr
foldr
insert []
(\n _ -> n + 1) 0
(:) y x
(\a x -> x ++ [a]) []
(++) []
28
Was macht die folgende Funktion?
mystery x = foldr (\a -> foldr (<->) [a]) [] x
where a <-> (b:x) = if a <= b then a:b:x else b:a:x
Programmieren in Haskell
29
foldr und foldl
*
/ \
a1 *
/ \
foldr (*) e
a2 .. <-----------\
*
/ \
an e
Programmieren in Haskell
:
/ \
a1
:
/ \
foldl (*) e
a2 .. ------------>
\
:
/ \
an []
*
/ \
*
an
/
..
/
*
/ \
e
a1
30
foldr und foldl
*
/ \
a1 *
/ \
foldr (*) e
a2 .. <-----------\
*
/ \
an e
:
/ \
a1
:
/ \
foldl (*) e
a2 .. ------------>
\
:
/ \
an []
foldr (*) e (reverse x)
=
*
/ \
*
an
/
..
/
*
/ \
e
a1
foldl (flip (*)) e x,
mit flip (*) = \a b -> b * a.
Programmieren in Haskell
30
foldl
foldl’’ :: (solution -> a -> solution) -> solution -> [a] -> solution
foldl’’ (*) e x = f x e
where f []
e = e
f (a:x) e = f x (e*a)
Programmieren in Haskell
31
reverse’’’’ = foldl (flip (:)) []
sum’’’
= foldl (+) 0
or’’’
= foldl (||) False
concat’’’ = foldl (++) []
Programmieren in Haskell
32
Speicher- und Zeitbedarf sum
sum’’ [1..9]
sum’’’ [1..9]
⇒
f [1..9]
⇒ f’ [1..9] 0
⇒
1 + f [2..9]
⇒ f’ [2..9] 1
⇒
1 + (2 + f [3..9])
⇒ f’ [3..9] 3
...
...
⇒
1 + (2 + ... + (9 + f []))
⇒ f’ [] 45
⇒
1 + (2 + ... + (9 + 0))
⇒ 45
⇒
45
Programmieren in Haskell
33
Speicher- und Zeitbedarf or
or’’ [False,True,False]
or’’’ [False,True,False]
⇒ f [False,True,False]
⇒ f’ [False,True,False] False
⇒ False || f [True,False]
⇒ f’ [True,False] (False || False)
⇒ f [True,False]
⇒ f’ [True,False] False
⇒ True || f [False]
⇒ f’ [False] (True || False)
⇒ True
⇒ f’ [False] True
⇒ f’ [] (False || True)
⇒ f’ [] True
⇒ True
Programmieren in Haskell
34
foldr1 und foldl1
foldr1 :: (a -> a -> a) -> [a] -> a
foldl1 :: (a -> a -> a) -> [a] -> a
foldr1 (*) = f
where f [a] = a
f (a:b:xs) = a * f (b:xs)
foldl1 (*) (x:xs) = foldl (*) x xs
Programmieren in Haskell
35
foldr1 und foldl1
foldr1 :: (a -> a -> a) -> [a] -> a
foldl1 :: (a -> a -> a) -> [a] -> a
foldr1 (*) = f
where f [a] = a
f (a:b:xs) = a * f (b:xs)
foldl1 (*) (x:xs) = foldl (*) x xs
righty, lefty :: [a] -> Tree a
righty = foldr1 Br . map Leaf
lefty = foldl1 Br . map Leaf
Programmieren in Haskell
35
foldm
:
*
/ \
/
\
a1
:
*
*
/ \
foldm (*) e
/
\
/
\
a2 .. ------------>
..
..
..
..
\
/
\
/
\
:
*
* ... *
*
/ \
/ \
/ \
/ \
/ \
an []
a1 a2 ai-1 ai ai+1 ai+2 an-1 an
Programmieren in Haskell
36
foldm :: (a
foldm (*) e
foldm (*) e
where f
Programmieren in Haskell
-> a -> a) -> a -> [a] -> a
[] = e
x = fst (f (length x) x)
n x = if n == 1 then (head x, tail
else let m
= n
(a,y) = f
(b,z) = f
in (a*b,z)
x)
‘div‘ 2
m
x
(n-m) y
37
foldm :: (a
foldm (*) e
foldm (*) e
where f
-> a -> a) -> a -> [a] -> a
[] = e
x = fst (f (length x) x)
n x = if n == 1 then (head x, tail
else let m
= n
(a,y) = f
(b,z) = f
in (a*b,z)
foldm1 (*) = foldm (*) (error "foldm1 []")
Programmieren in Haskell
x)
‘div‘ 2
m
x
(n-m) y
37
mergeList :: (Ord a) => [[a]] -> [a]
mergeList = foldm merge []
balanced :: [a] -> Tree a
balanced = foldm1 Br . map Leaf
msortBy, smsortBy :: (a -> a -> Bool) -> [a] -> [a]
msortBy (<=) = foldm (mergeBy (<=)) [] . map (\a -> [a])
smsortBy (<=) = foldm (mergeBy (<=)) [] . runsBy (<=)
Programmieren in Haskell
38
Fold auf Bäumen
foldTree :: (a -> b) -> (b -> b -> b) -> Tree a -> b
foldTree leaf br = f
where f (Leaf a) = leaf a
f (Br l r) = br (f l) (f r)
Programmieren in Haskell
39
Fold auf Bäumen
foldTree :: (a -> b) -> (b -> b -> b) -> Tree a -> b
foldTree leaf br = f
where f (Leaf a) = leaf a
f (Br l r) = br (f l) (f r)
size’
depth’
mergeTree’
mergeRuns’
Programmieren in Haskell
=
=
=
=
foldTree
foldTree
foldTree
foldTree
(\a -> 1) (+)
(\a -> 0) (\m n -> max m n + 1)
(\a -> [a]) merge
id merge
39
map und Kolleginnen
map :: (a -> b) -> [a] -> [b]
map f []
= []
map f (a:x) = f a:map f x
Programmieren in Haskell
40
Anwendung: Vektoren und Matrizen
type Vector a = [a]
type Matrix a = [Vector a]


3
2
8
17
0
1


[[3,8,0],[2,17,1]]
Programmieren in Haskell
41
(<*>):: (Num a) => a -> Vector a -> Vector a
k <*> x = map (\a -> k*a) x
Programmieren in Haskell
42
(<*>):: (Num a) => a -> Vector a -> Vector a
k <*> x = map (\a -> k*a) x
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith f (a:x) (b:y) = f a b:zipWith f x y
zipWith _ _
_
= []
Programmieren in Haskell
42
(<*>):: (Num a) => a -> Vector a -> Vector a
k <*> x = map (\a -> k*a) x
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith f (a:x) (b:y) = f a b:zipWith f x y
zipWith _ _
_
= []
(<+>) :: (Num a) => Vector a -> Vector a -> Vector a
x <+> y = zipWith (+) x y
(<.>) :: (Num a) => Vector a -> Vector a -> a
x <.> y = sum (zipWith (*) x y)
Programmieren in Haskell
42
zip :: [a] -> [b] -> [(a,b)]
zip = zipWith (\a b -> (a,b))
Programmieren in Haskell
43
zip :: [a] -> [b] -> [(a,b)]
zip = zipWith (\a b -> (a,b))
k <*> x = [k*a | a <- x]
x <+> y = [a+b | (a,b) <- zip x y]
x <.> y = sum [a*b | (a,b) <- zip x y]
Programmieren in Haskell
43
(<++>) :: (Num a) => Matrix a -> Matrix a -> Matrix a
a <++> b = zipWith (<+>) a b
Programmieren in Haskell
44
(<++>) :: (Num a) => Matrix a -> Matrix a -> Matrix a
a <++> b = zipWith (<+>) a b
(<**>) :: (Num a) => Matrix a -> Matrix a -> Matrix a
m <**> n = [[x <.> y | y <- transpose’ n] | x <- m]
Programmieren in Haskell
44
Induktionsschritt transpose
a11
a12
···
a1n
a11
a12
a1n
a2n
a21
a22
a2n
a21
a22
a31
..
.
a32
..
.
a3n
..
.
a31
..
.
a32
..
.
am1
am2
amn
am1
am2
Programmieren in Haskell
···
···
a3n
..
.
amn
45
Induktionsschritt transpose
a11
a12
···
a1n
a11
a12
a1n
a2n
a21
a22
a2n
a21
a22
a31
..
.
a32
..
.
a3n
..
.
a31
..
.
a32
..
.
am1
am2
amn
am1
am2
···
···
a3n
..
.
amn
transpose’ :: Matrix a -> Matrix a
transpose’ = foldr (zipWith (:)) (repeat [])
Programmieren in Haskell
45
Typpolymorphismus und Typklassen
(++) :: [a] -> [a] -> [a]
"hello " ++ "world"
⇒
"hello world"
[19, 9] ++ [7]
⇒
[19, 9, 7]
["hello ","world"] ++ ["it’s","me"]
⇒
["hello ","world","it’s","me"]
Programmieren in Haskell
46
Ein paar polymorphe Funktionen ...
head
tail
leaves
build
map
::
::
::
::
::
Programmieren in Haskell
[a] -> a
[a] -> [a]
Tree a -> [a]
[a] -> Tree a
(a -> b) -> ([a] -> [b])
47
Vergleichsoperator (<=)
(a,b) <= (c,d) = a < c || a == c && b <= d
[]
<= x
= True
(a:x) <= []
= False
(a:x) <= (b:y) = a < b || a == b && x <= y
Programmieren in Haskell
48
Typklasse Ord
isort :: (Ord a) => [a] -> [a]
Programmieren in Haskell
49
Typklasse Ord
isort :: (Ord a) => [a] -> [a]
Ord Integer
Ord Char
Ord a ∧ Ord b ⇒ Ord (a, b)
Ord a ⇒ Ord [a]
Programmieren in Haskell
49
isort ["Beginn","Anfall","Anfang"]
⇒
["Anfall","Anfang","Beginn"]
isort [(3,1),(1,7),(1,3),(2,2)]
⇒
[(1,3),(1,7),(2,2),(3,1)]
Verschiedene (<=)!
Programmieren in Haskell
50
Die Typklasse Show
show :: (Show a) => a -> String
Programmieren in Haskell
show 123
⇒
"123"
show [1, 2, 3]
⇒
"[1, 2, 3]"
show "123"
⇒
"\"123\""
51
Eq und Ord
unique :: (Eq a) => [a] -> [a]
element :: (Eq a) => a -> [a] -> Bool
insert :: (Ord a) => a -> [a] -> [a]
merge :: (Ord a) => [a] -> [a] -> [a]
Programmieren in Haskell
52
data Ordering = LT | EQ | GT
compare :: (Ord a) => a -> a -> Ordering
uniqueInsert’ a []
= [a]
uniqueInsert’ a x@(b:y) = case
LT
EQ
GT
Programmieren in Haskell
compare a b of
-> a:x
-> x
-> b:uniqueInsert’ a y
53
Die Typklasse Num ((+), (-), (*))
size :: (Num n) => Tree a -> n
depth :: (Num n, Ord n) => Tree a -> n
Programmieren in Haskell
54
Integral und Fractional
power :: (Num a, Integral b) => a -> b -> a
power x n
| n == 0
= 1
| n ‘mod‘ 2 == 0 = y
| otherwise
= y*x
where y = power (x*x) (n ‘div‘ 2)
Programmieren in Haskell
55
Untertypklassen
Eq
Show
/
\
/
Ord
Num
\
/ \
Integral Fractional
Programmieren in Haskell
56
Beispiel rationale Zahlen, (==)
data Rat = Rat Int Int
Falsche Definition (Rat 67 18 /= Rat 8241 2214):
Rat x y == Rat x’ y’ =
x == x’ && y == y’
Richtige Definition:
Rat x y == Rat x’ y’ = x*y’ == x’*y
Programmieren in Haskell
57
class- und instance-Deklarationen (Eq und Ord)
class Eq a where
(==), (/=) :: a -> a -> Bool
x /= y = not (x == y)
instance Eq Rat where
Rat x y == Rat x’ y’ =
Programmieren in Haskell
x*y’ == x’*y
58
Rat mit smart-Konstruktor
rat :: Int -> Int -> Rat
rat x y = norm (x * signum y) (abs y)
where norm x y = let d = gcd x y in Rat (x ‘div‘ d) (y ‘div‘ d)
Programmieren in Haskell
59
Beispiel Binärbäume
instance (Eq
Leaf a
(Br l r)
_
Programmieren in Haskell
a)
==
==
==
=> Eq (Tree a) where
Leaf b
= a == b
Br l’ r’ = l == l’ && r == r’
_
= False
60
Beispiel Binärbäume
instance (Eq
Leaf a
(Br l r)
_
a)
==
==
==
=> Eq (Tree a) where
Leaf b
= a == b
Br l’ r’ = l == l’ && r == r’
_
= False
Allgemeine Form einer Instanzdeklaration:
instance (C1 β1 ,...,Cm βm ) => C(T α1 . . . αn ) mit
{β1 , . . . , βm } ⊆ {α1 , . . . , αn }.
Programmieren in Haskell
60
Ord als Untertypklasse von Eq
class (Eq a) => Ord a where
compare
:: a -> a -> Ordering
(<), (<=), (>=), (>) :: a -> a -> Bool
max, min
:: a -> a -> a
compare x y | x == y
= EQ
| x <= y
= LT
| otherwise = GT
x
x
x
x
<=
<
>=
>
Programmieren in Haskell
y
y
y
y
=
=
=
=
compare
compare
compare
compare
x
x
x
x
y
y
y
y
/=
==
/=
==
GT
LT
LT
GT
61
max x y |
|
min x y |
|
Programmieren in Haskell
x >= y
otherwise
x <= y
otherwise
=
=
=
=
x
y
x
y
62
instance Ord Rat where
Rat x y <= Rat x’ y’ = x*y’ <= x’*y
Programmieren in Haskell
63
instance Ord Rat where
Rat x y <= Rat x’ y’ = x*y’ <= x’*y
instance
Nil
Leaf
Leaf
Leaf
Br _
Br _
Br l
Programmieren in Haskell
(Ord
<=
_ <=
a <=
_ <=
_ <=
_ <=
r <=
a) => Ord (Tree a) where
t
= True
Nil
= False
Leaf b
= a <= b
Br _ _
= True
Nil
= False
Leaf _
= False
Br l’ r’ = l < l’ || l == l’ && r <= r’
63
Ausgabe eines Baums
showTree
showTree
showTree
showTree
:: Tree String -> String
Nil
= "Nil"
(Leaf a) = "Leaf " ++ a
(Br l r) = "Br " ++ showTree l ++ " " ++ showTree r
showTree (Br (Br (Leaf "a") (Leaf "b")) Nil)
=> "Br Br Leaf a Leaf b Nil"
Programmieren in Haskell
64
Ausgabe eines Baums
showTree
showTree
showTree
showTree
:: Tree String -> String
Nil
= "Nil"
(Leaf a) = "Leaf " ++ a
(Br l r) = "Br " ++ showTree l ++ " " ++ showTree r
showTree (Br (Br (Leaf "a") (Leaf "b")) Nil)
=> "Br Br Leaf a Leaf b Nil"
leaves
leaves
leaves
leaves
:: Tree a -> [a]
Nil
= []
(Leaf a) = [a]
(Br l r) = leaves l ++ leaves r
Programmieren in Haskell
64
foldTree :: (a -> b) -> (b -> b -> b) -> Tree a -> b
foldTree leaf br = f
where f (Leaf a) = leaf a
f (Br l r) = br (f l) (f r)
Programmieren in Haskell
65
foldTree :: (a -> b) -> (b -> b -> b) -> Tree a -> b
foldTree leaf br = f
where f (Leaf a) = leaf a
f (Br l r) = br (f l) (f r)
myFoldTree :: b -> (a -> b) -> (b -> b -> b) -> Tree a -> b
myFoldTree nil leaf br = f
where f Nil
= nil
f (Leaf a) = leaf a
f (Br l r) = br (f l) (f r)
Programmieren in Haskell
65
myShowTree
nil
=
leaf a =
br l r =
Programmieren in Haskell
= myFoldTree nil leaf br where
"Nil"
"Leaf " ++ a
"Br " ++ l ++ " " ++ r
66
myShowTree
nil
=
leaf a =
br l r =
showTree’
showTree’
showTree’
showTree’
Programmieren in Haskell
= myFoldTree nil leaf br where
"Nil"
"Leaf " ++ a
"Br " ++ l ++ " " ++ r
:: Tree String -> String -> String
Nil s
= "Nil" ++ s
(Leaf a) s = "Leaf " ++ a ++ s
(Br l r) s = "Br " ++ showTree’ l (" " ++ showTree’ r s)
66
showTree’’
showTree’’
showTree’’
showTree’’
Programmieren in Haskell
:: Tree String -> ShowS
Nil
= showString "Nil"
(Leaf a) = showString "Leaf " . showString a
(Br l r) = showString "Br " . showTree’’ l . showChar ’ ’
. showTree’’ r
67
showTree’’
showTree’’
showTree’’
showTree’’
:: Tree String -> ShowS
Nil
= showString "Nil"
(Leaf a) = showString "Leaf " . showString a
(Br l r) = showString "Br " . showTree’’ l . showChar ’ ’
. showTree’’ r
type ShowS =
String -> String
showChar :: Char -> ShowS
showChar = (:)
showString :: String -> ShowS
showString = (++)
Programmieren in Haskell
67
Die Typklasse Show
class Show a where
showsPrec :: Int -> a -> ShowS
showList :: [a] -> ShowS
showList []
= showString "[]"
showList (a:x) = showChar ’[’ . shows a . showRest x
where showRest []
= showChar ’]’
showRest (a:x) = showString ", " . shows a . showRest x
Programmieren in Haskell
68
shows :: (Show a) => a -> ShowS
shows = showsPrec 0
show :: (Show a) => a -> String
show x = shows x ""
showParen :: Bool -> ShowS -> ShowS
showParen b p = if b then showChar ’(’ . p . showChar ’)’ else p
Programmieren in Haskell
69
instance Show Rat where
showsPrec p (Rat x y) = showParen (p > 9)
(showString "Rat " . showsPrec 10 x
. showsPrec 10 y)
Programmieren in Haskell
70
instance Show Rat where
showsPrec p (Rat x y) = showParen (p > 9)
(showString "Rat " . showsPrec 10 x
. showsPrec 10 y)
instance Show Rat where
showsPrec p (Rat x y) = showParen (p > 9)
(showString "Rat " . showsPrec 10 x
. showChar ’ ’
. showsPrec 10 y)
Programmieren in Haskell
70
instance (Show a) => Show (Tree a) where
showsPrec p Nil
= showString "Nil"
showsPrec p (Leaf a) = showParen (p > 9)
(showString "Leaf " . showsPrec 10 a)
showsPrec p (Br l r) = showParen (p > 9)
(showString "Br " . showsPrec 10 l
. showChar ’ ’ . showsPrec 10 r )
Programmieren in Haskell
71
Die Typklasse Num
class (Eq a, Show
(+), (-), (*)
negate
abs, signum
fromInteger
a)
::
::
::
::
=> Num a where
a -> a -> a
a -> a
a -> a
Integer -> a
x-y = x + negate y
Programmieren in Haskell
72
instance Num Rat where
Rat x y + Rat x’ y’
Rat x y * Rat x’ y’
negate (Rat x y)
abs (Rat x y)
signum (Rat x y)
fromInteger x
fromInt x
Programmieren in Haskell
=
=
=
=
=
=
=
Rat
Rat
Rat
Rat
Rat
Rat
Rat
(x*y’ + x’*y) (y*y’)
(x*x’) (y*y’)
(negate x) y
(abs x) (abs y)
(signum (x*y)) 1
(fromInteger x) 1
(fromInt x) 1
-- Hugs-spezifisch
73
Herunterladen