Einführung in Haskell

Ähnliche Dokumente
Funktionale Programmierung

Funktionale Programmierung

Was bisher geschah. deklarative Programmierung. funktionale Programmierung (Haskell):

WS 2011/2012. Georg Sauthoff 1. October 18, 2011

Funktionale Programmierung mit Haskell. Jan Hermanns

Funktionale Programmierung mit Haskell

Programmieren in Haskell Programmiermethodik

Was bisher geschah Funktionale Programmierung in Haskell: Algebraische Datentypen Pattern Matching Polymorphie Typklassen Rekursive Datentypen:

Programmieren in Haskell

Haskell, Typen, und Typberechnung. Grundlagen der Programmierung 3 A. Einige andere Programmiersprachen. Typisierung in Haskell

Grundprinzipien der funktionalen Programmierung

Einführung in die funktionale Programmierung

Funktionale Programmierung mit Haskell

Crashkurs Haskell Mentoring WiSe 2016/17. Anja Wolffgramm Freie Universität Berlin

expr :: Expr expr = Mul (Add (Const 3) (Const 4)) (Div (Sub (Const 73) (Const 37)) (Const 6))

Grundlagen der Programmierung 2 (1.C)

Typklassen, Eingabe und Monaden In Haskell

Typdeklarationen. Es gibt in Haskell bereits primitive Typen:

Zahlen in Haskell Kapitel 3

Tag 7. Pattern Matching und eigene Datentypen

Tutorium - Haskell in der Schule. Ralf Dorn - Dennis Buchmann - Felix Last - Carl Ambroselli

Beispiele: (Funktionen auf Listen) (3) Bemerkungen: Die Datenstrukturen der Paare (2) Die Datenstrukturen der Paare

Programmieren in Haskell

Funktionen höherer Ordnung

Funktionale Programmierung ALP I. Funktionen höherer Ordnung. Teil 2 SS Prof. Dr. Margarita Esponda. Prof. Dr.

Funktionale Programmiersprachen

Definieren Sie eine Funktion circlearea zur Berechnung der Fläche eines Kreises mit gegebenen Radius (Float).

2.5 Listen. Kurzschreibweise: [42; 0; 16] Listen werden mithilfe von [] und :: konstruiert.

Programmieren in Haskell

ALP I Einführung in Haskell

Übungen zur Vorlesung Funktionale Programmierung. Wintersemester 2012/2013 Übungsblatt 1

Funktionale Programmierung mit C++

Funktionale Programmierung

Imperative vs. Funktionale Programmierung

Programmieren in Haskell. Abstrakte Datentypen

Agenda. 1 Einleitung. 2 Binäre Bäume. 3 Binäre Suchbäume. 4 Rose Trees. 5 Zusammenfassung & Ausblick. Haskell Bäume. Einleitung.

CGI Programmierung mit Ha. Markus Schwarz

Programmtransformationen und Induktion in funktionalen Programmen

Funktionale Programmierung. ALP I Lambda-Kalkül. Teil IVb WS 2012/2013. Prof. Dr. Margarita Esponda. Prof. Dr. Margarita Esponda

Funktionale Programmierung mit C++

Java 8. Elmar Fuchs Grundlagen Programmierung. 1. Ausgabe, Oktober 2014 JAV8

Praktische Informatik 3: Funktionale Programmierung Vorlesung 3 vom : Algebraische Datentypen

Typ-basiertes Programmieren und Schließen in Funktionalen Sprachen

Funktionale Programmierung mit Haskell

Funktionale Programmierung mit Haskell

Proseminar: Perlen der Informatik II Haskell List comprehensions & Typklassen

Escher funktionale und logische Programmierung

Haskell zur Constraint-Programmierung HaL8

Programmieren in Haskell Einführung

Kapitel 7: Benutzerdefinierte Datentypen

[10] Software Transactional Memory in Haskell, Tortenwurf und Aufgabenblatt 7

ALP I. Funktionale Programmierung

Programmieren in C. Macros, Funktionen und modulare Programmstruktur. Prof. Dr. Nikolaus Wulff

Der λ-kalkül. Frank Huch. Sommersemester 2015

Einführung Datentypen Verzweigung Schleifen. Java Crashkurs. Kim-Manuel Klein May 4, 2015

C.3 Funktionen und Prozeduren

Tutoraufgabe 1 (Datenstrukturen in Haskell):

Praktische Informatik 3: Einführung in die Funktionale Programmierung Vorlesung vom : Rekursive Datentypen

Welche Informatik-Kenntnisse bringen Sie mit?

Praktikum Funktionale Programmierung Teil 1: Lexen und Parsen

Programmierung und Modellierung

Tutoraufgabe 1 (Zweierkomplement): Lösung: Programmierung WS16/17 Lösung - Übung 2

Funktionale Programmierung am Beispiel Haskell

Programmieren in C / C++ Grundlagen C 2

Programmieren in Haskell Felder (Arrays)

Grundlagen der Programmierung

Interpreter - Gliederung

Vorlesungsnotizen Funktionale Programmierung

Einführung Datentypen Verzweigung Schleifen Funktionen Dynamische Datenstrukturen. Java Crashkurs. Kim-Manuel Klein

RO-Tutorien 3 / 6 / 12

Programmieren in C++ Überladen von Methoden und Operatoren

THE GO PROGRAMMING LANGUAGE. Michael Karnutsch & Marko Sulejic

Probeklausur: Programmierung WS04/05

Kurze Einführung in die Programmiersprache C++ und in Root

Primitive Datentypen und Felder (Arrays)

Allgemeine Hinweise: TECHNISCHE UNIVERSITÄT MÜNCHEN. Name Vorname Studiengang Matrikelnummer. Hörsaal Reihe Sitzplatz Unterschrift

Proseminar Funktionales Programmieren. Stephan Kreutzer

Haskell, eine rein funktionale Programmiersprache

Deklarative Programmiersprachen

Algorithmen & Programmierung. Ausdrücke & Operatoren (1)

HASKELL KURS RALF HINZE. Institut für Informatik III Universität Bonn Römerstraße Bonn Germany

Werkzeuge zur Programmentwicklung

19. Funktional-reaktive Programmierung

Programmieren - C++ Funktions-Templates

Kontrollstrukturen, Pseudocode und Modulo-Rechnung

AuD-Tafelübung T-B5b

5.4 Klassen und Objekte

Theorie zu Übung 8 Implementierung in Java

Grundlagen der Programmierung

Transkript:

Einführung in Haskell Axel Stronzik 21. April 2008 1 / 43

Inhaltsverzeichnis 1 Allgemeines 2 / 43

Inhaltsverzeichnis 1 Allgemeines 2 Funktions- und Typdefinitionen 2 / 43

Inhaltsverzeichnis 1 Allgemeines 2 Funktions- und Typdefinitionen 3 Basisdatentypen 2 / 43

Inhaltsverzeichnis 1 Allgemeines 2 Funktions- und Typdefinitionen 3 Basisdatentypen 4 Typannotationen 2 / 43

Inhaltsverzeichnis 1 Allgemeines 2 Funktions- und Typdefinitionen 3 Basisdatentypen 4 Typannotationen 5 Algebraische Datentypen 2 / 43

Inhaltsverzeichnis 1 Allgemeines 2 Funktions- und Typdefinitionen 3 Basisdatentypen 4 Typannotationen 5 Algebraische Datentypen 6 Polymorphismus 2 / 43

Inhaltsverzeichnis 1 Allgemeines 2 Funktions- und Typdefinitionen 3 Basisdatentypen 4 Typannotationen 5 Algebraische Datentypen 6 Polymorphismus 7 PatternMatching 2 / 43

Inhaltsverzeichnis 1 Allgemeines 2 Funktions- und Typdefinitionen 3 Basisdatentypen 4 Typannotationen 5 Algebraische Datentypen 6 Polymorphismus 7 PatternMatching 8 Funtionen höherer Ordnung 2 / 43

Inhaltsverzeichnis 1 Allgemeines 2 Funktions- und Typdefinitionen 3 Basisdatentypen 4 Typannotationen 5 Algebraische Datentypen 6 Polymorphismus 7 PatternMatching 8 Funtionen höherer Ordnung 9 Lazy Evaluation 2 / 43

Inhaltsverzeichnis 1 Allgemeines 2 Funktions- und Typdefinitionen 3 Basisdatentypen 4 Typannotationen 5 Algebraische Datentypen 6 Polymorphismus 7 PatternMatching 8 Funtionen höherer Ordnung 9 Lazy Evaluation 10 Typklassen und Überladung 2 / 43

Inhaltsverzeichnis 1 Allgemeines 2 Funktions- und Typdefinitionen 3 Basisdatentypen 4 Typannotationen 5 Algebraische Datentypen 6 Polymorphismus 7 PatternMatching 8 Funtionen höherer Ordnung 9 Lazy Evaluation 10 Typklassen und Überladung 11 Ein-/Ausgabe 2 / 43

Vorteile funktionaler Programmiersprachen hohes Abstraktionsniveau, keine Manipulation von Speicherzellen keine Seiteneffekte, dies führt zu höherer Verständlichkeit und besseren Möglichkeiten zur Code-Optimierung Programmierung über Eigenschaften, nicht über den zeitlichen Ablauf kompakterer Source-Code (kürzere Entwicklungszeiten, lesbarere Programme, bessere Wartbarkeit) modularer Programmaufbau, Polymorphismus, Funktionen höherer Ordnung, damit auch eine hohe Wiederverwertbarkeit des Codes einfachere Korrektheitsbeweise 3 / 43

Strukturen in funktionalen Programmiersprachen Variablen entsprechen unbekannten Werten (nicht Speicherzellen!) Speicher ist nicht explizit verwendbar, sondern wird automatisch alloziert und freigegeben (Garbage Collection) Programme entsprechen Mengen von Funktions- und Typdefinitionen Programmablauf entspricht einer Reduktion von Ausdrücken (nicht einer Sequenz von Anweisungen) 4 / 43

Haskell Unix: GHCI (auf den Suns vorinstalliert unter: /home/haskell/bin/ghci ) Windows: Hugs (http://www.haskell.org/hugs) 5 / 43

Funktionen Die Definition einer Funktion in Haskell: f x 1... x n = e Mögliche Ausdrücke die man nutzen kann: Zahlen (3, 3.1415... ) Basisoperationen (3 + 4, 6 7) formale Parameter (Variablen) Funktionsanwendung ((f e 1... e n )) mit einer Funktion f und Ausdrücken e i bedingte Ausdrücke (if b then e1 else e2) 6 / 43

Beispielfunktionen Quadratfunktion: square x = x * x 7 / 43

Beispielfunktionen Quadratfunktion: square x = x * x Minimumsfunktion: min x y = if x <= y then x else y 7 / 43

Beispielfunktionen Fakultätsfunktion: n! = { 1 fallsn = 0 n (n 1)! sonst 8 / 43

Beispielfunktionen Fakultätsfunktion: Wird zu: n! = { 1 fallsn = 0 n (n 1)! sonst fac n = if n == 0 then 1 else n * fac (n-1) 8 / 43

Beispielfunktionen Fakultätsfunktion: Wird zu: n! = { 1 fallsn = 0 n (n 1)! sonst fac n = if n == 0 then 1 else n * fac (n-1) Fibonacci: fib1 n = if n == 0 then 0 else if n == 1 then 1 else fib1(n - 1) + fib1(n - 2) 8 / 43

Akkumulatortechnik Verbesserung fib fibn fibnp1 n = if n == 0 then fibn else fib fibnp1 (fibn + fibnp1) (n - 1) fib2 n = fib 0 1 n 9 / 43

Lokale Definitionen Unötige toplevel Funktion fib. 10 / 43

Lokale Definitionen Unötige toplevel Funktion fib. Besser lokal definieren: fib n = fib 0 1 n where fib fibn fibnp1 n =... 10 / 43

Lokale Definitionen Unötige toplevel Funktion fib. Besser lokal definieren: fib n = fib 0 1 n where fib fibn fibnp1 n =... Oder mit let: fib n = let fib fibn fibnp1 n =... in fib 0 1 n 10 / 43

Off-Side-Rule Sichtbarkeiten f x = e where g y = {Rumpf von g} {Rumpf von g geht weiter} {Rumpf von g geht weiter} h z = {Rumpf von h} {Rumpf von h geht weiter} {Rumpf von h geht weiter} k x y =... 11 / 43

Off-Side-Rule Sichtbarkeiten f x = e where g y = {Rumpf von g} {Rumpf von g geht weiter} {Rumpf von g geht weiter} h z = {Rumpf von h} {Rumpf von h geht weiter} {Rumpf von h geht weiter} k x y =... Im Rumpf von g: Variablen x, y, Funktionen f, g, h, k 11 / 43

Off-Side-Rule Sichtbarkeiten f x = e where g y = {Rumpf von g} {Rumpf von g geht weiter} {Rumpf von g geht weiter} h z = {Rumpf von h} {Rumpf von h geht weiter} {Rumpf von h geht weiter} k x y =... Im Rumpf von g: Variablen x, y, Funktionen f, g, h, k Im Rumpf von h: Variablen x, z, Funktionen f, g, h, k 11 / 43

Off-Side-Rule Sichtbarkeiten f x = e where g y = {Rumpf von g} {Rumpf von g geht weiter} {Rumpf von g geht weiter} h z = {Rumpf von h} {Rumpf von h geht weiter} {Rumpf von h geht weiter} k x y =... Im Rumpf von g: Variablen x, y, Funktionen f, g, h, k Im Rumpf von h: Variablen x, z, Funktionen f, g, h, k Im Rumpf von k: Variablen x, y, Funktionen f, k 11 / 43

Basisdatentypen Int Werte von 2 16 + 1 bis 2 16 1 (Integer, beliebig kleine/große Werte, durch Speicher beschränkt) Operationen: +, -, *, div, mod... Vergleiche: <=, >=, <, >, / =, == Bool Boolesche Werte: True, False Operationen: &&,, ==, /=, not Float Fließkommazahlen, geschrieben 0.3, 1.5e 2 Operationen wie bei Int mit / statt div und ohne mod Char Zeichen (ASCII), mit Werten: a, \n, \NUL, \214 Operationen: chr, ord 12 / 43

Typannotationen Alle Werte in Haskell haben einen Typ. Dieser kann mittels :: annotiert werden. Beispiele: 3 :: Integer 3 :: Int (3 == 4) True :: Bool square :: Int -> Int square x = (x :: Int) * (x :: Int) :: Int min :: Int -> Int -> Int 13 / 43

Algebraische Datentypen Eigenen τ Datentypen definieren mit dem Befehl data: data τ = c 1 τ 11... τ 1n1... c k τ k1... τ knk wobei: τ der neu definierte Typ ist c 1,... c k definierte Konstruktoren sind τ i1 bis τ ini, die Argumenttypen des Kontruktors c i sind, also c i :: τ i1 >... τ ini > τ 14 / 43

Beispiele data Color = Red Blue Yellow Red :: Color 15 / 43

Beispiele data Color = Red Blue Yellow Red :: Color data Complex = Complex Float Float Complex 3.0 4.2 :: Complex Anwendung: addc :: Complex -> Complex -> Complex addc (Complex r1 i1) (Complex r2 i2) = Complex (r1 + r2) (i1 + i2) 15 / 43

Beispiele data Color = Red Blue Yellow Auswertung von Red Error 16 / 43

Beispiele data Color = Red Blue Yellow deriving (Eq, Show) Auswertung von Red Error 16 / 43

Beispiele data List = Nil Cons Int List 17 / 43

Beispiele data List = Nil Cons Int List Anwendung: append :: List -> List -> List append Nil ys = ys append (Cons x xs) ys = Cons x (append xs ys) 17 / 43

Beispiele data List = Nil Cons Int List Anwendung: append :: List -> List -> List append Nil ys = ys append (Cons x xs) ys = Cons x (append xs ys) Vordefinierte Listen in Haskell: data [Int] = [] Int : [Int] 17 / 43

Beispiele data List = Nil Cons Int List Anwendung: append :: List -> List -> List append Nil ys = ys append (Cons x xs) ys = Cons x (append xs ys) Vordefinierte Listen in Haskell: data [Int] = [] Int : [Int] Anwendung: Berechnung der Länge einer Liste: 17 / 43

Beispiele data List = Nil Cons Int List Anwendung: append :: List -> List -> List append Nil ys = ys append (Cons x xs) ys = Cons x (append xs ys) Vordefinierte Listen in Haskell: data [Int] = [] Int : [Int] Anwendung: Berechnung der Länge einer Liste: length :: [Int] -> Int length [] = 0 length (x:xs) = 1 + length xs 17 / 43

Polymorphismus Bisher Jede Definition ist auf einen Typ festgelegt. Man muss für jeden Typ eigene Funktion/Konstruktor schreiben. 18 / 43

Polymorphismus Bisher Jede Definition ist auf einen Typ festgelegt. Man muss für jeden Typ eigene Funktion/Konstruktor schreiben. Verbesserung Polymorphismus. Einführen von Typvariablen. 18 / 43

Polymorphismus Bisher Jede Definition ist auf einen Typ festgelegt. Man muss für jeden Typ eigene Funktion/Konstruktor schreiben. Verbesserung Polymorphismus. Einführen von Typvariablen. Anwendung data [a] = [] a : [a] -- so nicht implementiert length :: [a] -> Int 18 / 43

Beispiele data Maybe a = Nothing Just a isnothing :: Maybe a -> Bool isnothing Nothing = True isnothing (Just _) = False data Tree a = Node (Tree a) a (Tree a) Empty height :: Tree a -> Int height Empty = 0 height (Node tl _ tr) = 1 + (max (height tl) (height tr)) 19 / 43

Beispiele Strings sind in Haskell als Typsynonym für Listen von Zeichen definiert: type String = [Char] Vereinigung zweier Typen: data Either a b = Left a Right b Tupel mit Mixfixnotation: data (,) a b = (,) a b -- oder (a, b) data (,,) a b c = (,,) a b c -- oder (a, b, c) 20 / 43

Pattern x (Variable) passt immer, x wird an aktuellen Ausdruck gebunden (Wildcart) passt immer, keine Bindung c pat 1... pat k (c k-stelliger Konstruktor und pat 1... pat k Pattern) passt, falls aktueller Wert c e 1... e k ist, und alle pat i auf alle e i passt. 21 / 43

Pattern x (Variable) passt immer, x wird an aktuellen Ausdruck gebunden (Wildcart) passt immer, keine Bindung c pat 1... pat k (c k-stelliger Konstruktor und pat 1... pat k Pattern) passt, falls aktueller Wert c e 1... e k ist, und alle pat i auf alle e i passt. x@pat ( as pattern ) passt, falls pat passt, zusätzliche Bindung von x an den aktuellen Ausdruck n + k Passt auf alle Zahlen größer gleich k, wobei n an aktuellen Wert minus k gebunden wird. 21 / 43

Nicht erlaubte Pattern Nicht erlaubt: gleiche Variable in einem Pattern eq :: a -> a -> Bool eq x x = True -- nicht erlaubt eq = False -- erlaubt 22 / 43

Der case Ausdruck Oft ist Patternmatching in bedingten Ausdrücken nützlich. Dazu gibt es den case Ausdruck: case e of pat1 -> e1... patn -> en Wichtig: Die Pattern für Ausdruck e müssen denselben Typ haben! 23 / 43

Guards Guards erlauben es zusätzliche Bedingungen an die linke Regelseite (Pattern) zu knüpfen. Beispiele: fac n n == 0 = 1 otherwise = n * fac (n - 1) take :: Int -> [a] -> [a] take n _ n <= 0 = [] take _ [] = [] take (n + 1) (x : xs) = x : take n xs Guards sind bei jedem Pattern Matching erlaubt, also auch bei case-, let und where-ausdrücken. 24 / 43

Funktionen höherer Ordnung Idee: Funktionen sind in funktionalen Programmiersprachen Bürger erster Klasse, d.h. können wie alle anderen Werte überall verwendet werden. Anwendungen sind unter anderem generische Programmierung und Programmschemata (Kontrollstrukturen). Vorteile: Höhere Wiederverwendbarkeit und große Modularität. 25 / 43

Funktionen höherer Ordnung Idee: Funktionen sind in funktionalen Programmiersprachen Bürger erster Klasse, d.h. können wie alle anderen Werte überall verwendet werden. Anwendungen sind unter anderem generische Programmierung und Programmschemata (Kontrollstrukturen). Vorteile: Höhere Wiederverwendbarkeit und große Modularität. Beispiel: ableitung :: (Float -> Float) -> (Float -> Float) 25 / 43

Funktionen höherer Ordnung Idee: Funktionen sind in funktionalen Programmiersprachen Bürger erster Klasse, d.h. können wie alle anderen Werte überall verwendet werden. Anwendungen sind unter anderem generische Programmierung und Programmschemata (Kontrollstrukturen). Vorteile: Höhere Wiederverwendbarkeit und große Modularität. Beispiel: ableitung :: (Float -> Float) -> (Float -> Float) Numerische Berechnung: f (x) = lim In Haskell: f (x+dx) f (x) [ dx 0 dx ] dx = 0.0001 ableitung f = f where f x = (f (x + dx) - f x) / dx 25 / 43

Anonyme Funktionen Um Namensraum zu schonen, können kleine Funktionen als anonyme Funktionen definieren. ableitung f = \x -> (f (x + dx) - f x) / dx ableitung hat hier einen funktionalen Wert. 26 / 43

Partielle Applikation Betrachte: add :: Int -> Int -> Int add x y = x + y 27 / 43

Partielle Applikation Betrachte: add :: Int -> Int -> Int add x y = x + y Mögliche andere Definitionen wären: add = \x y -> x + y add x = \y -> x + y 27 / 43

Partielle Applikation Partielle Applikation ist Typkorrekt, da > rechtsassoziativ ist. Es gilt also: a > b > c = a > (b > c) a > b > c (a > b) > c 28 / 43

Generische Programmierung filter p [] = [] filter p (x : xs) p x = x : filter p xs otherwise = filter p xs 29 / 43

Generische Programmierung filter :: (a -> Bool) -> [a] -> [a] filter p [] = [] filter p (x : xs) p x = x : filter p xs otherwise = filter p xs 29 / 43

Generische Programmierung filter :: (a -> Bool) -> [a] -> [a] filter p [] = [] filter p (x : xs) p x = x : filter p xs otherwise = filter p xs map f [] = [] map f (x : xs) = f x : map f xs 29 / 43

Generische Programmierung filter :: (a -> Bool) -> [a] -> [a] filter p [] = [] filter p (x : xs) p x = x : filter p xs otherwise = filter p xs map :: (a -> b) -> [a] -> [b] map f [] = [] map f (x : xs) = f x : map f xs 29 / 43

Generische Programmierung filter :: (a -> Bool) -> [a] -> [a] filter p [] = [] filter p (x : xs) p x = x : filter p xs otherwise = filter p xs map :: (a -> b) -> [a] -> [b] map f [] = [] map f (x : xs) = f x : map f xs foldr f e [] = e foldr f e (x : xs) = f x (foldr f e xs) 29 / 43

Generische Programmierung filter :: (a -> Bool) -> [a] -> [a] filter p [] = [] filter p (x : xs) p x = x : filter p xs otherwise = filter p xs map :: (a -> b) -> [a] -> [b] map f [] = [] map f (x : xs) = f x : map f xs foldr :: (a -> b -> b) -> b -> [a] -> b foldr f e [] = e foldr f e (x : xs) = f x (foldr f e xs) 29 / 43

Weitere Funktionen (.) :: (a -> b) -> ( c -> a ) -> c -> b (f. g) x = f (g x) flip :: (a -> b -> c ) -> b -> a -> c flip f x y = f y x const :: a -> b -> a const x _ = x 30 / 43

Lazy Evaluation Betrachte folgendes Haskel-Programm: f x = 1 h = h Mit folgender Anfrage: f h 31 / 43

Auswertungsstrategien Es gibt 2 interessante Auswertungsstrategien: Leftmost-Innermost (LI, strikte Funktionen): Alle Argumente eines Funktionsaufrufs müssen ausgewertet sein, bevor die Funktion angewendet werden kann. Leftmost-Outermost (LO, nicht-strikte Funktionen): Die Funktionen werden jeweils vor Argumenten ausgewertet. (Berechnungsvollständig) 32 / 43

unendliche Datenstrukturen Beispiel: from :: Num a => a -> [a] from n = n : from (n + 1) Nehme nun die bekannte Funktion take: take :: Int -> [a] -> [a] take n _ n <= 0 = [] take n [] = [] take n (x : xs) = x : take (n - 1) xs Nun ist z.b. folgendes möglich: take 3 (from 1) [1,2,3] 33 / 43

Typklassen und Überladung Betrachte folgende Funktion: Möglicher Typ der Funktion: elem x [] = False elem x (y : ys) = x == y elem x ys elem :: a -> [a] -> Bool 34 / 43

Typklassen und Überladung Betrachte folgende Funktion: Möglicher Typ der Funktion: elem x [] = False elem x (y : ys) = x == y elem x ys elem :: a -> [a] -> Bool Wo liegt das Problem? 34 / 43

Typklassen und Überladung Der Typ ist zu Allgemein, da a auch eine Funktion repräsentieren kann. Hier kann die Gleichheit nicht entschieden werden. Abhilfe schafft eine Einschränkung auf Typen, für die die Gleichheit definiert ist: elem :: Eq a => a -> [a] -> Bool 35 / 43

Beispiel Gleichheit für Bäume implementieren: data Tree = Empty Node Tree Int Tree instance Eq Tree where Empty == Empty = True (Node tl1 n1 tr1) == (Node tl2 n2 tr2) = tl1 == tl2 && n1 == n2 && tr1 == tr2 t1 /= t2 = not (t1 == t2) 36 / 43

Totale Ordnung Erweiterung der Eq Klasse zur totalen Ordnung: class Eq a => Ord a where compare :: a -> a -> Ordering (<), (<=), (>=), (>) :: a -> a -> Bool max, min :: a -> a -> a data Ordering = LT EQ GT 37 / 43

Klassen Weitere vordefinierte Klassen: Num zum Rechnen mit Zahlen (definiert (+), (-), (*), abs etc.) Show zum Umwandeln in Strings: show :: Show a => a -> String Read zum Konstruieren aus Strings 38 / 43

Ein-/Ausgabe Wichtig bei Ein-/Ausgabe ist die Reihenfolge dieser Aktionen. In Haskell realisiert durch den abstrakten Datentyp IO (), z.b.: putchar :: Char -> IO () Das Zusammensetzen von IO-Aktionen geschieht mittels des Sequenzoperators: (>>) :: IO () -> IO () -> IO () Sequenzialisierung mit Weitergabe durch den Bind-Operator: (>>=) : : IO a -> (a -> IO b) -> IO b 39 / 43

Beispiel putstr :: String -> IO () putstr "" = return () putstr (c : cs) = putchar c >> putstr cs getline :: IO String getline = getchar >>= \ c -> if c == \n then return "" else getline >>= \cs -> return (c : cs) 40 / 43

Do-Notation Die Do-Notation ist eine vereinfachte Schreibweise, die statt der Operatoren (>>=), (>>) nur Sequenzen verwendet. Mögliche Ausdrücke sind: pat <- e let pat = e e Beispiel: main = do c <- getchar putchar c -- ohne in Beachte: Schlüsselwort do leitet die Notation ein. Off-Side-Rule auch hier gültig. 41 / 43

Beispiele getline in Do-Notation: getline = do c <- getchar if c == \n then return "" else do cs <- getline return (c : cs) 42 / 43

Beispiele Ausgaben aller zwischenergebnisse von fac fac :: Int -> IO Int fac 0 = do putstr "1" return 1 fac (n + 1) = do facn <- fac n let facnp1 = (n + 1) * facn putstr ( : show facnp1) return facnp1 43 / 43