Programmieren in Haskell

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 diese Woche
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)
Definition von square:
square :: Int -> Int
square x = x * x
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) =>
=>
=>
=>
(3 + 4) * (3 + 4) (square)
7 * (3 + 4)
(+)
7 * 7
(+)
49
(*)
In Haskell wird allerdings die erste Reduktionsvariante gewählt.
Programmieren in Haskell
6
Listen
Die leere Liste: []
Eine Liste mit zwei Elementen: [1,2]
Der Operator ":"hängt ein Element vor eine Liste:
1:[] => [1]
1:2:[] => [1,2]
Die unendliche Liste: [1..]
Programmieren in Haskell
7
Funktionen auf Listen
Die Funktion take nimmt die ersten n Elemente von einer Liste:
take 0 xs
= []
take n (x:xs) = x : take (n-1) xs
Die Funktion drop verwirft die ersten n Elemente einer Liste:
drop 0 xs
= xs
drop n (x:xs) = drop (n-1) xs
Programmieren in Haskell
8
Gute und schlechte Reduktionswege
Definition von take:
take 0 xs
= []
take n (x:xs) = x : take (n-1) xs
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)
9
Gute und schlechte Reduktionswege
Definition von take:
take 0 xs
= []
take n (x:xs) = x : take (n-1) xs
Schlecht (warum?):
take 2 [1..] =>
=>
=>
=>
Programmieren in Haskell
take 2 (1:[2..])
(..)
take 2 (1:2:[3..])
(..)
take 2 (1:2:3:[4..]) (..)
...
10
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): True, False
&&, ||
• Listen
++, reverse, take
Programmieren in Haskell
11
• Zeichen (Char)
• Zeichenketten (String), wobei String = [Char]
Programmieren in Haskell
12
Ausdrücke haben Typen:
42 :: Int
3 + 4 :: Int
4.2 :: Float
True: Bool
"Hallo Welt!" :: String
[1,2,3] :: [Int]
Programmieren in Haskell
13
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 :: Temperatur
Programmieren in Haskell
14
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
15
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
16
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
16
Typklassen
In Haskell sind Typen in Klassen organisiert. Typen sind dabei Instanzen von Klassen.
Beispiele für Typklassen:
Eq: Überprüfung auf Gleichheit. Instanzen z.B.: Int, Float, Double, String
Ord: Ordnungsrelation. In der Klasse Ord sind die Operationen <,>,<=,>=
definiert. Instanzen z.B.: Int, Float, Double, String
Num: Umfasst die numerischen Typen, z.B. Int, Float, Double
Show: Werte eines Typs der Instanz der Klasse Show ist, lassen sich ausgeben. Z.B.
Int, Float, Double, String
Programmieren in Haskell
17
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
18
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
19
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
19
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
20
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
21
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
21
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
22
max’ 2 3 => 3
max’ "Robert" "Marc" => "Robert"
max’ [1,2,3] [1,2,4] => [1,2,4]
Programmieren in Haskell
23
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
24
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
25
Statt max’ 5 3 können wir auch (max’ 5) 3 schreiben. Welchen Typ hat der
Ausdruck max’ 5?
Programmieren in Haskell
26
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
26
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
26
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
27
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 square auf eine Liste anwenden:
map square [1,2,7,12,3,20] => [1,4,49,144,9,400]
Programmieren in Haskell
27
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
28
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)?
(+) :: Num a => a -> a -> a
(+1) :: Num a => a -> a
Programmieren in Haskell
28
map mit Strings
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x:map f xs
Die Funktion map funktioniert auch mit Listen von Strings:
map reverse ["Programmieren","in","Haskell"]
=> ["nereimmargorP","ni","lleksaH"]
Der Typ von map hier:
map :: (String -> String) -> [String] -> [String]
Programmieren in Haskell
29
map
Die Funktion length :: [a] -> Int berechnet die Länge einer Liste:
length []
= 0
length (x:xs) = 1 + length xs
Ein weiteres Beispiel für map:
map length ["Programmieren","in","Haskell"]
=> [13,2,7]
Der Typ von map hier:
map :: (String -> Int) -> [String] -> [Int]
Programmieren in Haskell
30
Ihre Aufgabe für diese Woche
Alle Beispiele ausprobieren, verändern, wieder
ausprobieren ...
Programmieren in Haskell
31
Herunterladen