Programmieren in Haskell Syntax und Semantik von Haskell Programmieren in Haskell 1 Was wir heute (und nächstes mal) machen • Datentypdefinitionen • Wertdefinitionen, Variablenbindungen • Musterbindungen • Funktionsbindungen • Bewachte Gleichungen • Lokale Definitionen mit where und let • Gültigkeitsbereiche • Fallunterscheidungen • Syntaktischer Zucker / Kernsprache Programmieren in Haskell 2 Datentypen, Datentypdefinitionen data Instrument = | | | Oboe HonkyTonkPiano Cello VoiceAahs data Musik Note Ton Dauer Pause Dauer Musik :*: Musik Musik :+: Musik Instr Instrument Musik Tempo GanzeZahl Musik Programmieren in Haskell = | | | | | 3 Wahrheitswerte data Bool = False | True Programmieren in Haskell -- vordefiniert 4 Ganze Zahlen data Ganz = Zero | Succ Ganz Zero, Succ Zero, Succ (Succ Zero), . . . Eingebaute Datentypen: Int und Integer Programmieren in Haskell 5 Tupeltypen data Pair a b = Pair a b data Triple a b c = Triple a b c Eingebaute Datentypen: (a,b), (a,b,c) Programmieren in Haskell 6 Listen data List a = Empty | Front a (List a) Eingebauter Datentyp: [a] Programmieren in Haskell 7 Allgemeine Form data T a1 . . . am = C1 t11 . . . t1n1 | ... | Cr tr1 . . . trnr T : Typkonstruktor; Ci : (Daten-)Konstruktoren; ai : Typvariablen; tij : Typen oder Typvariablen Programmieren in Haskell 8 Selektorfunktionen auf Tupeln fst :: (a,b) -> a fst (a,b) = a -- vordefiniert snd :: (a,b) -> b snd (a,b) = b -- vordefiniert Programmieren in Haskell 9 Selektorfunktionen auf Listen head :: [a] -> a head (x:xs) = x -- vordefiniert tail :: [a] -> [a] tail (x:xs) = xs -- vordefiniert Programmieren in Haskell 10 Selektorfunktionen auf Musik ton :: Musik -> Int ton (Note ton dauer) = ton dauer :: Musik -> Rational dauer (Note ton dauer) = dauer dauer (Pause dauer) = dauer Programmieren in Haskell 11 Typsynonyme type GanzeZahl type Bruch = Int = Rational type Ton type Dauer = GanzeZahl = Bruch Programmieren in Haskell 12 Nutzen und Gefahren von Typsynonymen type OrdList a = [a] sort :: [a] -> OrdList a sort xs = xs Typ ok? Ja Ergebnis geordnete Liste? Nein (jedenfalls nicht im allgemeinen) Programmieren in Haskell 13 Wertdefinitionen, Variablenbindungen theFinalAnswer :: Integer theFinalAnswer = 42 aShortList :: [Integer] aShortList = [1,2,3] helloWorld :: String helloWorld = "Hello World" monotonie :: Musik monotonie = c’ (1/1) :*: monotonie Programmieren in Haskell 14 Funktionsbindungen length :: [a] -> Int length [] = 0 length (a:as) = 1 + length as Programmieren in Haskell -- vordefiniert 15 Allgemeiner Fall f p11 . . . p1n = e1 ... = ... f pk1 . . . pkn = ek pij : Muster, ei : Ausdrücke Programmieren in Haskell 16 Bewachte Gleichungen member :: (Ord a) => a -> OrdList a -> Bool member a [] = False member a (b:bs) = a >= b && (a == b || member a bs) member a [] = False member a (b:bs) = if a < b then False else if a == b then True else member a bs member a [] member a (b:bs) | a < b | a == b | a > b Programmieren in Haskell = False = False = True = member a bs 17 Lokale Definitionen mit where sumSquares :: Int -> Int -> Int sumSquares x y = sqX + sqY where sqX = x * x sqY = y * y Programmieren in Haskell 18 Lokale Definitionen mit let sumSquares :: Int -> Int -> Int sumSquares x y = let sqX = x * x sqY = y * y in sqX + sqY Programmieren in Haskell 19 Abseitsregel • Das erste Zeichen der Definition unmittelbar nach dem where bestimmt die Einrücktiefe des neu eröffneten Definitionsblocks. • Zeilen, die weiter als bis zu dieser Position eingerückt sind, gelten als Fortsetzungen einer begonnenen lokalen Definition. • Zeilen auf gleicher Einrücktiefe beginnen eine neue Definition im lokalen Block. • Die erste geringer eingerückte Zeile beendet den lokalen Block. Programmieren in Haskell 20 Beispiel für Abseitsregel calc x y = calc1 x + calc2 y where calc1 x = squares x where squares x = x * x calc2 x = x * x * x Programmieren in Haskell 21 Fallunterscheidungen length :: [a] -> Int length [] = 0 length (a:as) = 1 + length as -- vordefiniert length’ :: [a] -> Int length’ as = case as of [] -> 0 a:as’ -> 1 + length’ as’ last’ :: [a] -> a last’ as = case reverse as of a:as’ -> a Programmieren in Haskell 22 Funktionsausdrücke Ist n + 1 ein Wert oder eine Funktion? Als Funktion: f n = n + 1 \n -> n + 1 Allgemeine Form eines Funktionsausdrucks: \p1 . . . pn -> e . \p1 p2 -> e als Abkürzung für \p1 -> \p2 -> e Programmieren in Haskell 23 Gestaffelte Funktionen add :: Integer -> Integer -> Integer add m n = m + n add’ :: Integer -> (Integer -> Integer) add’ = \m -> \n -> m + n Programmieren in Haskell 24 note :: Int -> Int -> Dauer -> Musik note oct h d = Note (12 * oct + h) d note Eine Note in einer beliebigen Oktave und von beliebiger Höhe und Dauer. note 2 Eine Note in der dritten Oktave und von beliebiger Höhe und Dauer. note 2 ef Die Note f in der dritten Oktave und von beliebiger Dauer. note 2 ef (1/4) ergibt Note 29 (1/4). Programmieren in Haskell 25 Syntaktischer Zucker / Kernsprache • Mustergleichungen / case-Ausdrücke length [] = 0 length (x:xs) = 1 + length xs length’ xs = case xs of [] -> 0 (x:xs) -> 1 + length’ xs • Funktionsdefinitionen / Funktions-Ausdrücke add m n = m + n add’ = \m -> \n -> m + n Programmieren in Haskell 26 • where-Klauseln / let-Ausdrücke double n = add0 (dup n) where dup a = (a,a) double n = let dup a = (a,a) in add0 (dup n) Programmieren in Haskell 27 Auswertung von Fallunterscheidungen case C e1 ...ek of {...; C x1 ...xk -> e;...} (case-Regel) ⇒ e[x1 /e1 , . . . , xn /en ] Programmieren in Haskell 28 abs :: (Ord a, Num a) => a -> a abs n = case n >= 0 of True -> n False -> -n encode :: (Num a) => Maybe a -> a encode x = case x of Nothing -> -1 Just n -> abs n encode (Just 5) ⇒ case Just 5 of {Nothing -> -1; Just n -> abs n} (Def. encode) ⇒ abs 5 (case − Regel) ⇒ case 5 >= 0 of {True -> 5; False -> -5} (Def. abs) ⇒ case True of {True -> 5; False -> -5} (Def. >=) ⇒ 5 Programmieren in Haskell (case − Regel) 29 Auswertung von Funktionsanwendungen (\x -> e) a ⇒ e[x/a] Programmieren in Haskell (β-Regel) (1) 30 abs = encode = \n -> case n >= 0 of {True -> n; False -> -n} \x -> case x of {Nothing -> -1; Just n -> abs n} encode (Just 5) (Def. encode) ⇒ (\x-> case x of {Nothing-> -1; Just n-> abs n}) (Just 5) ⇒ case Just 5 of {Nothing -> -1; Just n -> abs n} ⇒ abs 5 ⇒ (\n -> case n >= 0 of {True -> n; False -> -n}) 5 (Def. abs) ⇒ case 5 >= 0 of {True -> 5; False -> -5} (β − Regel) ⇒ case True of {True -> 5; False -> -5} (Def. (>=)) ⇒ 5 Programmieren in Haskell (β − Regel) (case − Regel) (case − Regel) 31 Auswertung von lokalen Definitionen let {x1 = e1 ;...;xn = en } in e ⇒ e[x1 /let {x1 = e1 ;...;xn = en } in e1 , . . . , (let-Regel) xn /let {x1 = e1 ;...;xn = en } in en ] Programmieren in Haskell 32 rep n a = let x = a:x in take n x rep 2 8 Programmieren in Haskell ⇒ let x = 8:x in take 2 x ⇒ take 2 (let x = 8:x in 8:x) (let − Regel) ⇒ take 2 (8:let x = 8:x in 8:x) (let − Regel) ⇒ 8:take 1 (let x = 8:x in 8:x) (Def. take) ⇒ 8:take 1 (8:let x = 8:x in 8:x) (let − Regel) ⇒ 8:8:take 0 (let x = 8:x in 8:x) (Def. take) ⇒ 8:8:[] (Def. take) (Def. rep) 33