Workshop Einführung in die Sprache Haskell Nils Rexin und Marcellus Siegburg [email protected] [email protected] itemis AG Niederlassung Leipzig Hochschule für Technik, Wirtschaft und Kultur Leipzig 20. Juni 2014 N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 1 / 27 Übersicht Übersicht 1 Haskell 2 Programmieren mit Haskell 3 Rekursionsmuster N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 2 / 27 Haskell Eigenschaften Allgemeines zu Haskell referentielle Transparenz (keine Nebenwirkung) Bedarfsauswertung (Lazy Evaluation) Funktionen höherer Ordnung Entwurfsmusterunterstützung kurzer Weg zwischen Spezifikation und Implementation ... N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 3 / 27 Programmieren mit Haskell Datentypen Datentyp eigener Datentyp Boolean data B o o l e a n = Wahr | F a l s c h d e r i v i n g Show Boolean ist der Typ Wahr, Falsch sind Konstruktoren | ist das Trennzeichen zwischen Konstruktoren deriving Show ≈ Vererbung .toString() in Java Einrückung beachten (Leerzeichen, Tabulatur) N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 4 / 27 Programmieren mit Haskell Datentypen Pattern Matching eigener Datentyp Boolean data B o o l e a n = Wahr | F a l s c h d e r i v i n g Show UND - Funktion und x y = case x of Falsch → Falsch Wahr → c a s e y o f Wahr → Wahr Falsch → Falsch N. Rexin, M. Siegburg ODER - Funktion oder x y = undefined Haskell-Einführung 20. Juni 2014 5 / 27 Programmieren mit Haskell Datentypen Pattern Matching verschiedene Möglichkeiten UND - Funktion und x y = case x of Falsch → Falsch Wahr → c a s e y o f Wahr → Wahr Falsch → Falsch . . . mit if-then-else und x y = i f x == F a l s c h then F a l s c h e l s e i f y == Wahr then Wahr else Falsch . . . ohne spezielle Einrückung und x y = c a s e x o f { F a l s c h → F a l s c h ; Wahr → u n d e f i n e d } N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 6 / 27 Programmieren mit Haskell Datentypen Pattern Matching verschiedene Möglichkeiten UND - Funktion und x y = case x of Falsch → Falsch Wahr → c a s e y o f Wahr → Wahr Falsch → Falsch . . . mit if-then-else und x y = i f x == F a l s c h then F a l s c h e l s e i f y == Wahr then Wahr else Falsch . . . ohne spezielle Einrückung und x y = c a s e x o f { F a l s c h → F a l s c h ; Wahr → u n d e f i n e d } N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 6 / 27 Programmieren mit Haskell Datentypen Pattern Matching verschiedene Möglichkeiten UND - Funktion und x y = case x of Falsch → Falsch Wahr → c a s e y o f Wahr → Wahr Falsch → Falsch . . . mit if-then-else und x y = i f x == F a l s c h then F a l s c h e l s e i f y == Wahr then Wahr else Falsch . . . ohne spezielle Einrückung und x y = c a s e x o f { F a l s c h → F a l s c h ; Wahr → u n d e f i n e d } N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 6 / 27 Programmieren mit Haskell Datentypen Pattern Matching mit un-/konkreten Konstruktoren UND - Funktion und Wahr Wahr = Wahr und = Falsch ODER - Funktion oder Falsch Falsch = Falsch oder = Wahr N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 7 / 27 Programmieren mit Haskell Datentypen Pattern Matching mit konkreten Konstruktoren Datentyp mit zwei ploymorphen Elementen; positionelle Notation data Paar a = Paar a a swap ( Paar x y ) = Paar y x Datentyp mit zwei ploymorphen Elementen; benannte Notation data Paar a = Paar { x : : a , y : : a } swap p = Paar ( y p ) ( x p ) N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 8 / 27 Programmieren mit Haskell Datentypen Pattern Matching mit konkreten Konstruktoren Datentyp mit zwei ploymorphen Elementen; positionelle Notation data Paar a = Paar a a swap ( Paar x y ) = Paar y x Datentyp mit zwei ploymorphen Elementen; benannte Notation data Paar a = Paar { x : : a , y : : a } swap p = Paar ( y p ) ( x p ) N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 8 / 27 Programmieren mit Haskell Datentypen Pattern Matching mit konkreten Konstruktoren und case-of-Ausdruck case-of-Ausdruck mit beliebigen Datentyp data D = Foo { a : : I n t , b : : I n t } | Bar { c : : I n t } d e r i v i n g Show f x = case x of Foo { a = x , b = y } → x + y Bar {} → c x Allgemein ist zubehalten Zu jedem Konstruktor eines Datentyps gibt es einen Zweig im case-of-Ausdruck. N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 9 / 27 Programmieren mit Haskell Datentypen Rekursiver Datentyp Datentyp für polymorphe Listen definieren data L i s t e a = N i l | Cons a ( L i s t e a ) d e r i v i n g Show Funktionen auf Liste a k e y ( Cons x x s ) = x next ( Cons x x s ) = x s N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 10 / 27 Programmieren mit Haskell Datentypen Rekursiver Datentyp Datentyp Liste mit benannten Komponenten data L i s t e a = N i l | Cons { k e y : : a , next : : d e r i v i n g Show L i s t e a} N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 11 / 27 Programmieren mit Haskell Datentypen Anwendung Aufgabe Datenstruktur die eine Linie, ein Rechteck und ein Kreis zusammenfasst Jedes Element soll eine Position enthalten (ganzzahlig) (Paar Int) Funktion, die den Flächeninhalt der oben genannten Objekte berechnet N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 12 / 27 Programmieren mit Haskell Datentypen Typen Typdefinitionen bei Funktionen explizit möglich Typdefinition n i c h t : : Boolean → Boolean n i c h t a = case a of Wahr → F a l s c h F a l s c h → Wahr Haskell kann den Typ inferieren (ableiten) N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 13 / 27 Programmieren mit Haskell Datentypen Rekursive Funktionen Aufgaben Können bei rekursiven Datenstrukturen verwendet werden Auswertung einer Boolean-Liste undListe undListe Nil → Cons a : : L i s t e Boolean → Boolean l i s t e = case l i s t e of Wahr a s → und a ( u n d L i s t e a s ) Listenverknüpfung verbinden : : Liste a → Liste a → Liste a v e r b i n d e n a b = case a of Nil → b Cons a ’ a s → Cons a ’ ( v e r b i n d e n a s b ) N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 14 / 27 Programmieren mit Haskell Datentypen Rekursive Funktionen Funktion, die eine Liste umkehrt Typ der Umpkehrfunktion umkehren : : Liste a → Liste a Ein Paar von zwei Listen gleicher Länge, gleichen Typs in einer Paar-Liste zusammenführen Aus einer Paar Liste ein Paar mit zwei neuen Listen erzeugen N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 15 / 27 Programmieren mit Haskell Datentypen Map Anonyme Funktionen Funktion wird nicht benannt Verwendung eines Lambda-Ausdrucks Beispiel addAnonym : : B o o l e a n → B o o l e a n → B o o l e a n addAnonym = ( λ a b → c a s e a o f Wahr → b Falsch → Falsch ) addAnonym2 = ( λ a → ( λ b → c a s e a o f Wahr → b Falsch → Falsch ) ) N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 16 / 27 Programmieren mit Haskell Datentypen Map Funktionen höherer Ordnung Funktion als Rückgabewert Funktion als Parameter Beispiel o p e r a t i o n P a a r : : ( a → a → b ) → Paar a → b o p e r a t i o n P a a r f ( Paar a b ) = f a b undPaar : : Paar B o o l e a n → B o o l e a n undPaar p = o p e r a t i o n P a a r ( λ a b → und a b ) p N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 17 / 27 Programmieren mit Haskell Datentypen Map Definition Idee: Auf alle Elemente einer rekursiven Struktur die selbe Funktion anwenden Definition von Map: Map für Listen mapListe mapListe Nil → Cons a N. Rexin, M. Siegburg : : (a → b) → Liste a → Liste b f l = case l of Nil a s → Cons ( f a ) ( m a p L i s t e f a s ) Haskell-Einführung 20. Juni 2014 18 / 27 Programmieren mit Haskell Datentypen Map Aufgaben und auf alle Boolean-Paare in einer Liste anwenden Aus einer Liste mit geometrischen Objekten alle Quadrate durch Wahr in einer neu erzeugten Boolean-Liste hervorheben N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 19 / 27 Rekursionsmuster Motivation Rekursive Funktionen auf Listen summe l i s t e = c a s e l i s t e o f Nil → 0 Cons x x s → x + summe x s l a e n g e l i s t e = case l i s t e of Nil → 0 Cons xs → 1 + laenge xs u n d L i s t e l i s t e = case l i s t e of Nil → Wahr Cons x x s → und x ( u n d L i s t e x s ) → gemeinsames Muster? N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 20 / 27 Rekursionsmuster Fold auf Listen (1) Muster (Pseudocode) f l i s t e = case l i s t e of Nil → ? exp1 ? Cons x x s → ? exp2 ? x ( f x s ) Abstraktion des gemeinsamen Musters foldListe : : b → (a → b → b) → Liste a → b f o l d L i s t e exp1 exp2 l i s t e = c a s e l i s t e o f Nil → exp1 Cons x x s → exp2 x ( f o l d L i s t e exp1 exp2 x s ) N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 21 / 27 Rekursionsmuster Fold auf Listen (2) Rekursive Funktionen auf Listen summe l i s t e = c a s e l i s t e o f Nil → 0 Cons x x s → x + summe x s laenge l i s t e = case l i s t e of Nil → 0 Cons xs → 1 + laenge xs undListe l i s t e = case l i s t e of Nil → Wahr Cons x x s → und x ( u n d L i s t e x s ) Definition mit Fold summe ’ laenge ’ l i s t e = f o l d L i s t e 0 ( λx r e s u l t → 1 + r e s u l t ) l i s t e undListe ’ l i s t e = f o l d L i s t e 0 ( λx r e s u l t → x + r e s u l t ) l i s t e l i s t e = f o l d L i s t e Wahr ( λx r e s u l t → und x r e s u l t ) l i s t e N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 22 / 27 Rekursionsmuster Fold auf Listen (3) Übung: Ersetze undefined verbinden : : Liste a → Liste a → Liste a verbinden a b = f o l d L i s t e undefined undefined a umkehren : : L i s t e a → L i s t e a → L i s t e a umkehren l i s t e = f o l d L i s t e u n d e f i n e d u n d e f i n e d l i s t e N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 23 / 27 Rekursionsmuster Fold im Allgemeinen für jeden Konstruktor K eines Types bekommt fold ein Parameter p p hat die gleiche Stelligkeit wie K Parametertypen von K entsprechen den Parametertypen von p (fast, s. Rekursion) Vergleiche Liste a mit foldListe data L i s t e a = N i l | Cons a ( L i s t e a ) foldListe N. Rexin, M. Siegburg : : b → (a → b → b) → Liste a → b Haskell-Einführung 20. Juni 2014 24 / 27 Rekursionsmuster Fold auf Bäumen Übung: Ersetze ? und undefined data Baum a = B l a t t | Zweig (Baum a ) a (Baum a ) foldBaum : : ? → ? → Baum a → b foldBaum b l a t t z w e i g baum = u n d e f i n e d s u m m e S c h l u e s s e l : : Baum I n t e g e r → I n t e g e r s u m m e S c h l u e s s e l baum = foldBaum u n d e f i n e d u n d e f i n e d baum hoehe : : Baum a → I n t e g e r hoehe baum = foldBaum u n d e f i n e d u n d e f i n e d baum i n o r d e r S c h l u e s s e l : : Baum a → L i s t e a i n o r d e r S c h l u e s s e l baum = foldBaum u n d e f i n e d u n d e f i n e d baum N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 25 / 27 Zusammenfassung Zusammenfassung Aufgabe Datentypen mit Pattern Matching (case-of) rekursive Datentypen (Liste, Baum) Polymorphie Typ-Definition Funktionen höherer Ordnung (mapListe) Lambda-Ausdruck Besuchermuster (fold) auf Listen, Bäumen Quelltext Link: http://www.imn.htwk-leipzig.de/~nrexin/hal9 N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 26 / 27 Vielen Dank für Ihre Aufmerksamkeit N. Rexin, M. Siegburg Haskell-Einführung 20. Juni 2014 27 / 27