Programmieren in Haskell Syntax und Semantik von Haskell Peter Steffen Universität Bielefeld Technische Fakultät 13.11.2009 1 Programmieren in Haskell Was wir heute machen Datentypdefinitionen Wertdefinitionen, Variablenbindungen Musterbindungen Funktionsbindungen Bewachte Gleichungen Lokale Definitionen mit where und let Gültigkeitsbereiche Fallunterscheidungen Syntaktischer Zucker / Kernsprache 2 Programmieren in Haskell Datentypen, Datentypdefinitionen 3 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 Wahrheitswerte data Bool = False | True 4 -- vordefiniert Programmieren in Haskell Ganze Zahlen data Ganz = Zero | Succ Ganz Zero, Succ Zero, Succ (Succ Zero), . . . Eingebaute Datentypen: Int und Integer 5 Programmieren in Haskell Tupeltypen data Pair a b = Pair a b data Triple a b c = Triple a b c Eingebaute Datentypen: (a,b), (a,b,c) 6 Programmieren in Haskell Listen data List a = Empty | Front a (List a) Eingebauter Datentyp: [a] 7 Programmieren in Haskell Allgemeine Form data T a1 . . . am = C1 t11 . . . t1n1 | ... | Cr tr 1 . . . trnr T : Typkonstruktor; Ci : (Daten-)Konstruktoren; ai : Typvariablen; tij : Typen oder Typvariablen 8 Programmieren in Haskell Allgemeine Form data T a1 . . . am = C1 t11 . . . t1n1 | ... | Cr tr 1 . . . trnr T : Typkonstruktor; Ci : (Daten-)Konstruktoren; ai : Typvariablen; tij : Typen oder Typvariablen 8 Programmieren in Haskell Selektorfunktionen auf Tupeln 9 fst :: (a,b) -> a fst (a,b) = a -- vordefiniert snd :: (a,b) -> b snd (a,b) = b -- vordefiniert Programmieren in Haskell Selektorfunktionen auf Listen 10 head :: [a] -> a head (x:xs) = x -- vordefiniert tail :: [a] -> [a] tail (x:xs) = xs -- vordefiniert Programmieren in Haskell Selektorfunktionen auf Musik ton :: Musik -> Int ton (Note ton dauer) = ton dauer :: Musik -> Rational dauer (Note ton dauer) = dauer dauer (Pause dauer) = dauer 11 Programmieren in Haskell Typsynonyme 12 type GanzeZahl type Bruch = Int = Rational type Ton type Dauer = GanzeZahl = Bruch Programmieren in Haskell 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) 13 Programmieren in Haskell 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) 13 Programmieren in Haskell 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) 13 Programmieren in Haskell 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) 13 Programmieren in Haskell 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) 13 Programmieren in Haskell Wertdefinitionen, Variablenbindungen aShortList :: [Integer] aShortList = [1,2,3] helloWorld :: String helloWorld = "Hello World" monotonie :: Musik monotonie = c’ (1/1) :*: monotonie 14 Programmieren in Haskell Funktionsbindungen length :: [a] -> Int length [] = 0 length (a:as) = 1 + length as 15 -- vordefiniert Programmieren in Haskell Allgemeiner Fall f p11 . . . p1n = e1 ... = ... f pk1 . . . pkn = ek pij : Muster, ei : Ausdrücke 16 Programmieren in Haskell 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 17 = False = False = True = member a bs Programmieren in Haskell Lokale Definitionen mit where sumSquares :: Int -> Int -> Int sumSquares x y = sqX + sqY where sqX = x * x sqY = y * y 18 Programmieren in Haskell Lokale Definitionen mit let sumSquares :: Int -> Int -> Int sumSquares x y = let sqX = x * x sqY = y * y in sqX + sqY 19 Programmieren in Haskell 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. 20 Programmieren in Haskell 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 21 Programmieren in Haskell 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 22 Programmieren in Haskell 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 23 Programmieren in Haskell Gestaffelte Funktionen add :: Integer -> Integer -> Integer add m n = m + n add’ :: Integer -> (Integer -> Integer) add’ = \m -> \n -> m + n 24 Programmieren in Haskell Gestaffelte Funktionen 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). 25 Programmieren in Haskell 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 26 Programmieren in Haskell where-Klauseln / let-Ausdrücke 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) 27 Programmieren in Haskell Auswertung von Fallunterscheidungen case C (e1 ) . . . (ek )of{. . . ; C (x1 ) . . . (xk )− > e; . . .}(case-Regel) ⇒ e[x1 /e1 , . . . , xn /en ] 28 Programmieren in Haskell 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) 29 ⇒ abs 5 (case − Regel) ⇒ ⇒ case 5 >= 0 of {True -> 5; False -> -5} case True of {True -> 5; False -> -5} ⇒ 5 (Def. abs) (Def. >=) (case − Regel) Programmieren in Haskell Auswertung von Funktionsanwendungen (\(x)− > (e))(a) ⇒ e[x/a] 30 (β-Regel) Programmieren in Haskell 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) 31 ⇒ case Just 5 of {Nothing -> -1; Just n -> abs n} (β − Regel) ⇒ abs 5 ⇒ (\n -> case n >= 0 of {True -> n; False -> -n}) 5 ⇒ case 5 >= 0 of {True -> 5; False -> -5} (β − Regel) ⇒ case True of {True -> 5; False -> -5} (Def. (>=)) ⇒ 5 (case − Regel) (Def. abs) (case − Regel) Programmieren in Haskell Auswertung von lokalen Definitionen let {x1 = e1 ;...;xn = en } in e ⇒ e[x1 / xn / 32 let {x1 = e1 ;...;xn = en } in e1 , . . . ,(let-Regel) let {x1 = e1 ;...;xn = en } in en ] Programmieren in Haskell rep n a = let x = a:x in take n x rep 2 8 ⇒ 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) 8:take 1 (let x = 8:x in 8:x) (let − Regel) (Def. take) ⇒ (Def. rep) 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) ⇒ 33 8:8:[] (Def. take) Programmieren in Haskell