Funktionale Programmierung Jörg Kreiker Uni Kassel und SMA Solar Technology AG Wintersemester 2011/2012 1 Teil III Muster und Fälle raten 2 Muster • bekannte Muster: Variablen, Wildcards, leere/nicht-leere Listen • Muster erlauben gleichzeitiges Testen und Zerlegen strukturierter Werte • Muster müssen linear sein, keine Variable mehr als einmal • Vorkommen von Mustern: • Musterbindungen • λ Abstraktionen • Funktionsbindungen • Listencomprehensions 3 Haskell Muster pat F | | | | | c x K pat1 . . . patk x@pat ˜pat Wildcard Literal Variable k -stelliger Konstruktor ’as’ Muster irrefutable 4 Musterabgleich • Muster werden mit Werten verglichen (matched) • Mögliche Resultate • Erfolg: Menge von Bindngen, [x1 7→ v1 , . . . , xn 7→ vn ] ∈ E • Fehler, ↓ • Divergenz, ⊥ • Achtung: Werte können beliebig (un)reduziert sein • Musterabgleich erzwingt Reduktion (forcing) • Reduktion nur soweit wie nötig 5 Musterabgleich formal Muster p gegen Wert v: p ]v ∈ Id → Val ∪ {⊥, ↓} Muster p x c Wert v v v c0 ⊥ K p1 . . . pk K v1 . . . vk K 0 v1 . . . vk ⊥ x@p ˜p v v p ]v [] [x 7→ v ] if c == c 0 then [] else ↓ ⊥ p1 ]v1 ] . . . ] pk ]vk ↓ ⊥ [x 7→ v ] ] p ]v lazy pattern, nächste Folie ] ist linksassoziativ, vereinigt Umgebungen und ergibt ↓ /⊥ beim ersten Vorkommen. 6 Lazy Patterns • ∼ p ]v, wobei x1 , . . . , xk frei sind in p • falls p ]v =↓ oder p ]v = ⊥ dann [x1 7→ ⊥, . . . , xk 7→ ⊥] • Auswertung genau dann wenn eines der xi verwendet wird • Bindung impliziert nicht Auswertung! • Beispiel case v of ∼ p → e (λx1 x2 . . . xk → e ) (case v of p → x1 ) . . . (case v of p → xk ) 7 Dynamische Semantik mit Mustern • Lambda λp1 . . . pk → e case (x1 , . . . , xk ) of (p1 , . . . , pk ) → e xi sind unverbrauchte Variablen. • Let let {p1 = e1 ; . . . ; pk = ek } in e let (∼ p1 , . . . , ∼ pk ) = (e1 , . . . , ek ) in e let p = e1 in e case e1 of ∼ p → e let p = e1 in e let p = fix (λ∼ p → e1 ) in e • Bindung in let Ausdrücken ist implizit lazy • fix ist ein Fixpunkt Operator • Listencomprehensions und Funktionsdefinitionen werden analog zu case und λ Ausrücken reduziert 8 Beispiele • let x = ⊥ in 0 =⇒ 0 • let (x,y) = ⊥ in 0 =⇒ 0 lazy let, irrefutable • (\(x,y) -> 0) ⊥ =⇒ ⊥ refutable pattern • (\˜(x,y) -> 0) ⊥ =⇒ 0 irrefutable pattern • (\(x,y) -> 0) (⊥, ⊥) =⇒ 0 • (\(x:xs) -> (x:x:xs)) ⊥ =⇒ ⊥ • (\˜(x:xs) -> (x:x:xs)) ⊥ =⇒ ⊥ : ⊥ : ⊥ • irrefutable: lazy patterns, Variablen, Wildcards, as-Muster mit irrefutable Teilmustern • refutable: Konstruktoren, Literale 9 STOP 10 Case Ausdrücke exp F case exp of { pat1 match1 ; . . . ; patn matchn } Jedes matchi hat die Form | gi1 → ei1 | gi2 → ei2 | . . . | gik → eiki where declsi • • • • • g ist ein Guard vom Typ Bool k , n ≥ 1, jedes ki ≥ 1 Layout nach of pat → exp pat | True → exp Beispiel: map f x = case x of [] -> [z] where z = f 0 (y:ys) | y < 0 -> (f (-y)) : z | y > 0 -> (f y) : z | otherwise -> z where z = map f ys 11 Dynamische Semantik von case case e of {p1 m1 ; . . . ; pn mn } in Umgebung E, wobei jedes mi die Form | gi1 → ei1 | gi2 → ei2 | . . . | gik → eiki where declsi hat. 1. Gleiche e gegen p1 , p2 , . . . bis zum ersten Erfolg, pi , ab; andernfalls 3. 2. Werte gi1 zu giki aus in E0 = E ⊕ pi ]e ⊕ [[declsi ]] 2.1 Falls alle gij zu False auswerten: 1. 2.2 Das erste j, für das gij zu True auswertet: Werte eij in E0 aus 3. gebe ⊥ zurück 12 Musterbindungen p | g1 = e1 ... | gm = em where {decls} • Einfache Musterbindung p = e erzeugt Bindungen p ]e • allgemeiner Fall zurückführen auf den einfachen: p = let decls in if g1 then e1 else if g2 then e2 else ... if gm then em else ⊥ 13 Funktionsbindungen x ... x p11 . . . p1k m1 pn1 . . . pnk mk mi = | gi1 = ei1 | gimi = eimi where {declsi } • aufeinanderfolgend, gleiche Anzahl an Mustern, linear • bindet x an einen funktionalen Wert λx1 . . . xk → case (x1 , . . . xk ) of (p11 , . . . , p1k ) m1 ... • funktionale Werte können an Infixoperatoren gebunden werden f f ‘map‘ ‘map‘ [] (x:xs) = = [] f x : f ‘map‘ xs 14 STOP 15