Kapitel 2

Werbung
Programmieren in Haskell
Wir steigen ein ...
Programmieren in Haskell
1
Was wir heute machen
• Umfrage: Wer hat den Hugs ausprobiert?
• Ausdrücke und Werte
• Datentypen
• Funktionen
• Aufgabe für’s Wochenende
Programmieren in Haskell
2
Ausdrücke und Werte
Ausdrücke repräsentieren Werte. Ausdrücke sind zum Beispiel:
42
6*7
answer
reverse ".therdegmu lam raw etsiL eseiD"
let { fib 0 = 1; fib 1 = 1; fib n = fib (n-2) + fib (n-1) } in fib 10
Programmieren in Haskell
3
Ausdrücke können einfach sein oder komplex. Einfach:
49
Komplex:
square (3+4)
Die “einfachste” Form eines Ausdrucks wird Normalform genannt.
Programmieren in Haskell
4
Reduktion von Ausdrücken
Reduktion, Auswertung, Vereinfachung sind synonyme Begriffe und beschreiben
den Prozess, einen Ausdruck in seine einfachste Form (Normalform) zu überführen.
Beispiel: Mit
square :: Int -> Int
square x = x * x
können wir square (3+4) folgendermaßen reduzieren (das Symbol => verwenden
wir, um eine Reduktion zu kennzeichnen):
square (3 + 4) => square 7 (+)
=> 7 * 7
(square)
=> 49
(*)
(Die rechte Spalte benennt die Funktionen, deren Definitionen in der Reduktion
verwendet wurden)
Programmieren in Haskell
5
Reduktionsvarianten
Der obige Weg ist nicht der einzige, um den Ausdruck square (3+4) zu reduzieren.
Eine Alternative ist:
square (3 + 4) =>
=>
=>
=>
Programmieren in Haskell
(3 + 4) * (3 + 4) (square)
7 * (3 + 4)
(+)
7 * 7
(+)
49
(*)
6
Gute und schlechte Reduktionswege
Gut (so wird es in Haskell gemacht):
take 2 [1..] =>
=>
=>
=>
=>
Programmieren in Haskell
take 2 (1:[2..])
1:take 1 [2..]
1:take 1 (2:[3..])
1:2:take 0 [3..]
1:2:[]
(..)
(take)
(..)
(take)
(take)
7
Gute und schlechte Reduktionswege
Gut (so wird es in Haskell gemacht):
take 2 [1..] =>
=>
=>
=>
=>
take 2 (1:[2..])
1:take 1 [2..]
1:take 1 (2:[3..])
1:2:take 0 [3..]
1:2:[]
(..)
(take)
(..)
(take)
(take)
Schlecht (warum?):
take 2 [1..] =>
=>
=>
=>
Programmieren in Haskell
take 2 (1:[2..])
(..)
take 2 (1:2:[3..])
(..)
take 2 (1:2:3:[4..]) (..)
...
7
Datentypen
Datentypen sind Mengen von Werten, zusammen mit auf diesen Werten
definierten Operationen (Funktionen).
“Eingebaute” Datentypen in Haskell sind zum Beispiel:
• Ganze Zahlen (Integer, Int)
Funktionen darauf sind z.B.: +, -, square
• Fließkommazahlen (Float, Double)
• Wahrheitswerte (Bool)
&&, ||
• Listen
++, reverse, take
• Zeichenketten (String)
Programmieren in Haskell
8
Ausdrücke haben Typen:
42 :: Int
3 + 4 :: Int
"Hallo Welt!" :: String
[1,2,3] :: [Int]
Programmieren in Haskell
9
Neue Datentypen
Wir können auch unsere eigenen Datentypen definieren:
data Einheit
= Celsius
|
Fahrenheit |
Kelvin
data Temperatur = Temp Float Einheit
deriving (Eq,Show)
deriving (Eq,Show)
Damit können wir zum Beispiel folgenden Ausdruck bilden:
Temp 506 Kelvin
Programmieren in Haskell
10
Funktionen auf neuen Datentypen
Wir können nun zum Beispiel Einheiten umrechnen:
celsius_nach_kelvin :: Temperatur -> Temperatur
celsius_nach_kelvin (Temp t Celsius) = Temp (t + 273.15) Kelvin
kelvin_nach_fahrenheit :: Temperatur -> Temperatur
kelvin_nach_fahrenheit (Temp t Kelvin) = Temp (t*9/5-459.67) Fahrenheit
Programmieren in Haskell
11
Oder etwas eleganter:
umrechnen :: Temperatur -> Einheit -> Temperatur
umrechnen (Temp t Celsius) Kelvin
= Temp (t + 273.15) Kelvin
umrechnen (Temp t Kelvin) Fahrenheit = Temp (t*9/5-459.67) Fahrenheit
Programmieren in Haskell
12
Oder etwas eleganter:
umrechnen :: Temperatur -> Einheit -> Temperatur
umrechnen (Temp t Celsius) Kelvin
= Temp (t + 273.15) Kelvin
umrechnen (Temp t Kelvin) Fahrenheit = Temp (t*9/5-459.67) Fahrenheit
umrechnen (Temp 506 Kelvin) Fahrenheit
=> Temp 451.13 Fahrenheit
umrechnen (Temp (-100) Celsius) Kelvin
=> Temp 173.15 Kelvin
Programmieren in Haskell
12
Typklassen
In Haskell sind Typen in Klassen organisiert. Hier ein Ausschnitt der
Klassen-Hierarchie:
Enum
Eq
Show
/ \ /
Ord Num
/ \ / \
Ix Real Fractional
/
Integral
Typen sind Instanzen von Klassen.
Programmieren in Haskell
13
Klassendefinitionen
Klassendefinitionen sind Vereinbarungen von “Schnittstellen”. Zum Beispiel:
Wenn ein Typ Instanz der Klasse Eq ist, kann ich mich darauf verlassen, daß ich
Elemente dieses Typs auf Gleichheit testen kann. Zum Beispiel ist der Typ Int eine
Instanz der Klasse Eq; ich kann also zwei Ints auf Gleichheit testen:
3 == 4 => False
Und außerdem auf Ungleichheit:
3 /= 4 => True
Programmieren in Haskell
14
Die Klasse Eq ist folgendermaßen definiert:
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
Wegen deriving Eq können wir automatisch auch Temperaturen vergleichen:
Temp 506 Kelvin == Temp 506 Kelvin => True
Programmieren in Haskell
15
Die Klasse Eq ist folgendermaßen definiert:
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
Wegen deriving Eq können wir automatisch auch Temperaturen vergleichen:
Temp 506 Kelvin == Temp 506 Kelvin => True
Aber:
Temp 506 Kelvin == umrechnen (Temp 506 Kelvin) Fahrenheit => False
Programmieren in Haskell
15
Eigene Instanzen definieren
Jetzt werden wir die Gleichheit auf Temperaturen selbst definieren. Daher definieren
wir den Datentyp Temperatur diesmal ohne deriving Eq:
data Temperatur = Temp Float Einheit deriving Show
Programmieren in Haskell
16
instance Eq Temperatur where
(Temp t Celsius)
== (Temp u Celsius)
=
(Temp t Fahrenheit) == (Temp u Fahrenheit) =
(Temp t Kelvin)
== (Temp u Kelvin)
=
(Temp t Kelvin)
== (Temp u Fahrenheit)
= umrechnen (Temp t Kelvin) Fahrenheit ==
Programmieren in Haskell
t == u
t == u
t == u
Temp u Fahrenheit
17
instance Eq Temperatur where
(Temp t Celsius)
== (Temp u Celsius)
=
(Temp t Fahrenheit) == (Temp u Fahrenheit) =
(Temp t Kelvin)
== (Temp u Kelvin)
=
(Temp t Kelvin)
== (Temp u Fahrenheit)
= umrechnen (Temp t Kelvin) Fahrenheit ==
t == u
t == u
t == u
Temp u Fahrenheit
Temp 506 Kelvin == umrechnen (Temp 506 Kelvin) Fahrenheit => True
Programmieren in Haskell
17
Eine eigene Show-Instanz
Temp 100 Celsius => Temp 100.0 Celsius
Temp 451 Fahrenheit => Ein Film von Francois Truffaut
Programmieren in Haskell
18
Eine eigene Show-Instanz
Temp 100 Celsius => Temp 100.0 Celsius
Temp 451 Fahrenheit => Ein Film von Francois Truffaut
instance Show Temperatur where
show (Temp t Fahrenheit) | round t == 451 = "Ein Film von Francois Truffaut"
show (Temp t e) = "Temp " ++ show t ++ " " ++ show e
Programmieren in Haskell
18
Typkontexte
Oft wollen wir uns nicht auf einen Typ festlegen, aber doch Zugehörigkeit zu einer
oder mehrerer Klassen verlangen. Zum Beispiel: Anstatt die Funktion max nur auf
Ints zu definieren (unsere Funktion maxi vom letzten Mal)
maxi :: Int -> Int -> Int
maxi n m
| n >= m
= n
| otherwise = m
können wir sie für alle vergleichbaren Typen definieren (Ord a wird Typkontext
genannt):
max’ :: Ord a => a -> a -> a
max’ n m
| n >= m
= n
| otherwise = m
Programmieren in Haskell
19
max’ 2 3 => 3
max’ "Robert" "Marc" => "Robert"
max’ [1,2,3] [1,2,4] => [1,2,4]
Programmieren in Haskell
20
Funktionen
Funktionen bilden Eingabewerte auf Ausgabewerte ab. Als Beispiel nochmal die
Quadrat-Funktion:
square :: Int -> Int
square x = x * x
square hat ein Argument vom Typ Int (nämlich x), und das Ergebnis ist auch vom
Typ Int.
Man sagt: "Die Funktion square hat den Typ Int nach Int."
Programmieren in Haskell
21
Funktionen können auch mehr als ein Argument haben. Zum Beispiel hat unsere
Funktion max’ zwei Argumente:
max’ :: Ord a => a -> a -> a
max’ n m
| n >= m
= n
| otherwise = m
Man sagt: "Die Funktion max’ hat den Typ a nach a nach a (mit Kontext Ord a)."
Programmieren in Haskell
22
Statt max’ 5 3 können wir auch (max’ 5) 3 schreiben. Welchen Typ hat der
Ausdruck max’ 5?
Programmieren in Haskell
23
Statt max’ 5 3 können wir auch (max’ 5) 3 schreiben. Welchen Typ hat der
Ausdruck max’ 5?
Fragen wir den Hugs:
Main> :t max’ 5
max’ 5 :: (Ord a, Num a) => a -> a
Programmieren in Haskell
23
Statt max’ 5 3 können wir auch (max’ 5) 3 schreiben. Welchen Typ hat der
Ausdruck max’ 5?
Fragen wir den Hugs:
Main> :t max’ 5
max’ 5 :: (Ord a, Num a) => a -> a
max’ 5 kann als neue Funktion aufgefaßt werden:
max’ 5 => f where
f m | 5 >= m
= 5
| otherwise = m
Programmieren in Haskell
23
Funktionen höherer Ordnung
Funktionen sind “first-class values”, d.h. sie können Argumente anderer Funktionen
sein. Dieses Prinzip wird uns durchgehend begleiten! Als Beispiel hier die Funktion
map, die eine weitere Funktion auf die Elemente einer Liste anwendet:
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x:map f xs
Programmieren in Haskell
24
Funktionen höherer Ordnung
Funktionen sind “first-class values”, d.h. sie können Argumente anderer Funktionen
sein. Dieses Prinzip wird uns durchgehend begleiten! Als Beispiel hier die Funktion
map, die eine weitere Funktion auf die Elemente einer Liste anwendet:
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x:map f xs
Jetzt können wir unsere Funktion max’ 5 auf eine Liste anwenden:
map (max’ 5) [1,2,7,12,3,20] => [5,5,7,12,5,20]
Programmieren in Haskell
24
Oder wir erhöhen jedes Element der Liste um 1:
map (+1) [1,2,7,12,3,20] => [2,3,8,13,4,21]
Welchen Typ hat (+1)?
Programmieren in Haskell
25
Oder wir erhöhen jedes Element der Liste um 1:
map (+1) [1,2,7,12,3,20] => [2,3,8,13,4,21]
Welchen Typ hat (+1)?
(+1) :: Num a => a -> a
Programmieren in Haskell
25
Ihre Aufgabe für’s Wochenende
Alle Beispiele ausprobieren, verändern, wieder
ausprobieren ...
Programmieren in Haskell
26
Herunterladen