Funktionale Programmierung mit Haskell. Jan Hermanns



Ähnliche Dokumente
Funktionale Programmierung mit Haskell

Programmieren in Haskell Einführung

Funktionale Programmierung

Typdeklarationen. Es gibt in Haskell bereits primitive Typen:

Das Typsystem von Scala. L. Piepmeyer: Funktionale Programmierung - Das Typsystem von Scala

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

Einführung in die Programmierung

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

Erwin Grüner

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

Der Aufruf von DM_in_Euro 1.40 sollte die Ausgabe 1.40 DM = Euro ergeben.

ALP I. Funktionale Programmierung

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

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

Scala kann auch faul sein

Computeranwendung und Programmierung (CuP)

Objektorientierte Programmierung

Einführung in die Programmierung (EPR)

Kapitel 7 des Buches, von Java-Selbstbau nach Scala-Library portiert Christoph Knabe

Programmierkurs Java

Einführung in die Programmierung

Diana Lange. Generative Gestaltung Operatoren

Grundlagen der Programmierung Prof. H. Mössenböck. 3. Verzweigungen

Einfache Ausdrücke Datentypen Rekursive funktionale Sprache Franz Wotawa Institut für Softwaretechnologie

Gebundene Typparameter

Datentypen. Agenda für heute, 4. März, Pascal ist eine streng typisierte Programmiersprache

Modellierung und Programmierung 1

Einführung in die Programmierung

Fragen. f [ ] = [ ] f (x : y : ys) = x y : f ys f (x : xs) = f (x : x : xs) Wozu evaluiert f [1, 2, 3] (Abkürzung für f (1 : 2 : 3 : [ ]))?

Einführung in die Java- Programmierung

Grundlagen der Programmierung Prof. H. Mössenböck. 14. Schrittweise Verfeinerung

Die Definition eines Typen kann rekursiv sein, d.h. Typ-Konstruktoren dürfen Elemente des zu definierenden Typ erhalten.

Institut für Programmierung und Reaktive Systeme 25. August Programmier-Labor Übungsblatt. int binarysearch(int[] a, int x),

1. Teilklausur. Modul "OOPM Vorlesung/Übung" Gruppe A

CGI Programmierung mit Ha. Markus Schwarz

Graphic Coding. Klausur. 9. Februar Kurs A

Felder. November 5, 2014

Einführung in das Programmieren Prolog Sommersemester Teil 2: Arithmetik. Version 1.0

Vorkurs C++ Programmierung

Grundlegende Datentypen

Einfache Arrays. Annabelle Klarl. Einführung in die Informatik Programmierung und Softwareentwicklung

FB Informatik. Fehler. Testplan

Programmierung 2. Übersetzer: Code-Erzeugung. Sebastian Hack. Klaas Boesche. Sommersemester

Allgemeines. Verschiedene Sprachkonzepte C-Sprachfamilie C-ähnliche Programmiersprachen Allgemeines zu C. #include <stdio.h>

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Grundprinzipien der funktionalen Programmierung

1 Vom Problem zum Programm

Java 7. Elmar Fuchs Grundlagen Programmierung. 1. Ausgabe, Dezember 2011 JAV7

Klausur in Programmieren

Gliederung. n Teil I: Einleitung und Grundbegriffe. n Teil II: Imperative und objektorientierte Programmierung

Übungsblatt 3: Algorithmen in Java & Grammatiken

Java Kurs für Anfänger Einheit 4 Klassen und Objekte

Gliederung. Tutorium zur Vorlesung. Gliederung. Gliederung. 1. Gliederung der Informatik. 1. Gliederung der Informatik. 1. Gliederung der Informatik

7 Rechnen mit Polynomen

Übungen Programmieren 1 Felix Rohrer. Übungen

Was ist Logische Programmierung?

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

WS 2012/2013. Robert Giegerich. 21. November 2012

Client-Server-Beziehungen

Programmierung in C. Grundlagen. Stefan Kallerhoff

Unterprogramme. Funktionen. Bedeutung von Funktionen in C++ Definition einer Funktion. Definition einer Prozedur

Adressen. Praktikum Funktionale Programmierung Organisation und Überblick. Termine. Studienleistung

C-Probeklausur (Informatik 1; Umfang: C, Teil 1; SS07)

Die Gleichung A x = a hat für A 0 die eindeutig bestimmte Lösung. Für A=0 und a 0 existiert keine Lösung.

II. Grundlagen der Programmierung. 9. Datenstrukturen. Daten zusammenfassen. In Java (Forts.): In Java:

HASKELL KAPITEL 2.1. Notationen: Currying und das Lambda-Kalkül

Übungskomplex Felder (1) Eindimensionale Felder Mehrdimensionale Felder

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Kontrollstrukturen, Strukturierte Programmierung

Deklarationen in C. Prof. Dr. Margarita Esponda

Neue Features in C# 2.0

Grundlegende Datentypen

Grundlagen der Programmierung 2. Bäume

Prüfung Computation, Programming

Modul 122 VBA Scribt.docx

Zwischenablage (Bilder, Texte,...)

Übersicht Programmablaufsteuerung

Druckerscriptsprache

Algorithmen mit Python

Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung: Lösungsvorschlag

Das erste Programm soll einen Text zum Bildschirm schicken. Es kann mit jedem beliebigen Texteditor erstellt werden.

Informationsblatt Induktionsbeweis

Funktionale Programmierung (in Clojure)

Grundlegende Datentypen

Funktionale Programmierung Grundlegende Datentypen

Suchmaschinen. Universität Augsburg, Institut für Informatik SS 2014 Prof. Dr. W. Kießling 23. Mai 2014 Dr. M. Endres, F. Wenzel Lösungsblatt 6

Fachgebiet Informationssysteme Prof. Dr.-Ing. N. Fuhr. Programmierung Prof. Dr.-Ing. Nobert Fuhr. Übungsblatt Nr. 6

IT-Basics 2. DI Gerhard Fließ

Java Kurs für Anfänger Einheit 5 Methoden

Grundlagen von Python

Einführung in die Programmierung für Wirtschaftsinformatik

WS 2013/2014. Robert Giegerich. 11. Dezember 2013

Quadratische Gleichungen

Klausur in Programmieren

Kontrollstrukturen - Universität Köln

Kontrollstrukturen und Funktionen in C

Programmieren in C. Rekursive Funktionen. Prof. Dr. Nikolaus Wulff

Die Programmiersprache C99: Zusammenfassung

Grundlagen. Kapitel 1

Enigmail Konfiguration

Transkript:

Funktionale Programmierung mit Haskell Jan Hermanns 1

Programmiersprachen imperativ deklarativ konventionell OO logisch funktional Fortran Smalltalk Prolog Lisp C Eiffel ML Pascal Java Haskell 2

von Neumann Flaschenhals Not only is this tube a literal bottleneck for the data traffic problem, but, more importantly, it is an intellectual bottleneck that has kept us tied to wordat-a-time thinking instead of encouraging us to think in terms of the larger conceptual units of the task at hand. - John Backus, 1978 3

Haskell Benannt nach Haskell Brooks Curry Hervorgegangen aus Miranda 1988 erste Definition des Haskell-Standards aktueller Standard Haskell98 Besondere Eigenschaften Unterstützt Literate-Programming polymorphes Typsystem (samt Inferenzsystem!) lazy rein funktional 4

Was bedeutet das konkret? Es gibt weder Variablen noch Zuweisungen int i=0; i=i+1; geht nicht! Es gibt keine Schleifenkonstrukte for (int i=0; i<x; i++) gibt es nicht! while (true) {} gibt es auch nicht! Keine sequentielle Abarbeitung des Programm-Codes D.h. Umdenken ist angesagt! 5

Was macht dieses Programm? qs( a, lo, hi ) int a[], hi, lo; { int h, l, p, t; if (lo < hi) { l = lo; h = hi; p = a[hi]; do { while ((l < h) && (a[l] <= p)) l = l+1; while ((h > l) && (a[h] >= p)) h = h-1; if (l < h) { t = a[l]; a[l] = a[h]; a[h] = t; } } while (l < h); template <typename T> void qsort (T *result, T *list, int n) { if (n == 0) return; T *smallerlist, *largerlist; smallerlist = new T[n]; largerlist = new T[n]; T pivot = list[0]; int numsmaller=0, numlarger=0; for (int i = 1; i < n; i++) if (list[i] < pivot) smallerlist[numsmaller++] = list[i]; else largerlist[numlarger++] = list[i]; qsort(smallerlist,smallerlist,numsmaller); qsort(largerlist,largerlist,numlarger); int pos = 0; for ( int i = 0; i < numsmaller; i++) result[pos++] = smallerlist[i]; } } t = a[l]; a[l] = a[hi]; a[hi] = t; qs( a, lo, l-1 ); qs( a, l+1, hi ); } result[pos++] = pivot; for ( int i = 0; i < numlarger; i++) result[pos++] = largerlist[i]; delete [] smallerlist; delete [] largerlist; 6

und in Haskell... qsort [] = [] qsort (x:xs) = qsort lessx ++ [x] ++ qsort greatereqx where lessx = [e e<-xs, e < x] greatereqx = [e e<-xs, e >= x] 7

Einfache Funktionen Namen von Funktionen und Parametern müssen mit Kleinbuchstaben beginnen Beispiele: hello = Hello, world! square x = x * x add x y = x + y 8

Funktionen mit Guards Ein Guard ist ein bewachter Ausdruck Abarbeitung der Guards von oben nach unten Der Ausdruck hinter dem ersten passenden Guard wird ausgewertet maximum x y x >= y = x otherwise = y 9

Rekursive Funktionen -- Bildet die Summe 1+2+...+n. sumup n n == 0 = 0 otherwise = n + sumup (n-1) sumup 2 2 + sumup (2-1) 2 + 1 + sumup (1-1) 2 + 1 + 0 3 sumup (-2) (-2) + sumup (-3) (-2) + (-3) + sumup (-4) usw. 10

Die error Funktion Aufruf von sumup mit negativen Werten führt zu Endlos-Rekursion! Eine bessere Definition wäre daher -- Bildet die Summe 1+2+...+n. -- Parameter n darf nicht negativ sein sumup n n == 0 = 0 n > 0 = n + sumup (n-1)! otherwise = error n is negative! 11

Lokale Definitionen Mit dem Schlüsselwort where kann man lokale Definitionen vornehmen Erhöht die Lesbarkeit -- Summiert die Quadrate von x und y. sumsquares x y = square x + square y where square n = n * n 12

Operatoren Operatoren wie +, *, -, / sind normale Funktionen, die zwei Parameter erwarten. Mit den Zeichen!#$%&*+./<=>?\^ :-~ können eigene Operatoren definiert werden. x +* y = (x + y) * (x + y) 2 +* 3 25 Prefix-Schreibweise ebenfalls möglich. (+) 3 4 7 Jede 2-argumentige Funktionen kann mittels Backquotes als Operator verwendet werden. 2 `max` 3 3 13

Layout-Regeln Blöcke werden durch { und } getrennt Einzelne Definitionen werden durch, getrennt Bei Verwendung von Einrückung kann jedoch auf die Trennsymbole verzichtet werden. vgl. Quicksort Definition 14

Typen Haskell ist stark getypt d.h. zur Laufzeit können keine Fehler durch Anwendung von Funktionen auf Argumente des falschen Typs entstehen Haskell hat ein statisches Typsystem die Typen aller Ausdrücke sind zur Übersetzungszeit bekannt sie werden sogar automatisch inferiert Hakell ist polymorph d.h. Funktionen können nicht nur für einzelne Typen, sondern auch für ganze Typklassen definiert werden 15

Typdeklarationen Typen werden mit Hilfe der Symbole :: und -> definiert. Vordefinierte Basistypen sind u.a. Bool, Int, Integer, Float, Double, Char Typnamen beginnen mit Grossbuchstaben daysinweek :: Int daysinweek = 7 square :: Int -> Int square x = x * x add :: Int -> Int -> Int add x y = x + y 16

Typsynonyme Mit dem Schlüsselwort type werden Typsynonyme definiert type Age = Int isadult :: Age -> Bool isadult x = x >= 18 17

Listen Listen sind die zentralen Datenstrukturen in funktionalen Programmen Listen sind Folgen von Werten des gleichen Typs. z.b. [Bool], [Int], [[Char]] Manche Listenfunktionen haben einen eindeutigen Typ sum :: [Int] -> Int Für andere Listenfunktionen ist der Typ der Elemente jedoch irrelevant!? length [1, 2, 3] length [ a, b, c ] 18

Typvariablen Mit Hilfe von Typvariablen wird ausgedrückt, daß kein bestimmter Typ erwartet wird. generischer Polymorphismus Für Typvariablen werden üblicherweise Kleinbuchstaben verwendet length :: [a] -> Int id :: a -> a id x = x 19

Konstruktion von Listen [] ist die leere Liste Mittels : wird ein Element am Anfang der Liste angefügt Der Typ von : ist a -> [a] -> [a] 1 : [] ergibt [1] 1:(2:[]) ergibt [1,2] : ist rechts-assoziativ 1:(2:(3:[])) 1:2:3:[] 20

Syntaktischer Zucker [1, 2, 3] 1:2:3:[] Strings sind ganz normale Listen type String = [Char] abc [ a, b, c ] Aufzählungen [1.. 4] [1, 2, 3, 4] [1, 3.. 10] [1, 3, 5, 7, 9] [ a, c.. n ] "acegikm" [1.. ] die Liste von 1 bis 21

Pattern Matching Funktionsdefinitionen können auseinander gezogen werden. Abhängig vom übergebenen Parameter wird dann die entsprechende Definition angewendet. not :: Bool -> Bool not True = False not False = True not not x :: Bool -> Bool x = False otherwise = True 22

Wildcards Das funktioniert auch für mehrere Parameter. and :: Bool -> Bool -> Bool and True True = True and False True = False and True False = False and False False = False Mit Hilfe des Wildcard-Patterns _ kann die obige Definition vereinfacht werden. and :: Bool -> Bool -> Bool and True True = True and = False 23

List Patterns Eine Liste von Patterns kann selbst auch als Pattern verwendet werden. foo :: String -> Bool foo [ a, _, _] = True foo _ = False Das gilt auch für die leere Liste. isempty :: [a] -> Bool isempty [] = True isempty _ = False 24

Mit dem cons Operator : können nicht nur Listen, sondern auch Patterns gebaut werden. foo :: String -> Bool foo ( a :_) = True foo _ = False Die Variablen eines Patterns werden bei einem Match an die übergebenen Werte gebunden. startswith :: String -> Char -> Bool startswith [] _ = False startswith (x:_) y x == y = True otherwise = False "Hello" `startswith` 'H' True 25

Jeder Parameter einer Funktionsdefinition muss einen eigenen, eindeutigen Namen tragen. Daher ist die folgende Definition leider nicht gültig: startswith :: String -> Char -> Bool startswith [] _ = False startswith (x:_) x = True ERROR - Repeated variable "x" in pattern 26

Standard Listenfunktionen head head (x:_) tail tail (_:xs) last last [x] last (_:xs) :: [a] -> a = x :: [a] -> [a] = xs :: [a] -> a = x = last xs init :: [a] -> [a] init [x] = [] init (x:xs) = x : init xs (++) :: [a] -> [a] -> [a] [] ++ ys = ys (x:xs) ++ ys = x : (xs ++ ys) 27

Die Funktion last liefert das letzte Element einer Liste. last :: [a] -> a (1) last [x] = x (2) last (_:xs) = last xs last [1,2,3] (2) last [2,3] (2) last [3] (1) 3

Die Funktion init liefert die Liste ohne das letzte Element. init :: [a] -> [a] (1) init [x] = [] (2) init (x:xs) = x : init xs init [1,2,3] (2) 1 : init [2,3] (2) 1 : 2 : init [3] (1) 1 : 2 : [] [1, 2]

Der Operator ++ hängt zwei Listen aneinander. (++) :: [a] -> [a] -> [a] (1) [] ++ ys = ys (2) (x:xs) ++ ys = x : (xs ++ ys) [1,2,3] ++ [4,5] (2) 1 : ([2,3] ++ [4,5]) (2) 1 : (2 : ([3] ++ [4,5])) (2) 1 : (2 : (3 : ([] ++ [4,5])))(1) 1 : (2 : (3 : ([4,5]))) 1 : (2 : ([3,4,5])) 1 : ([2,3,4,5]) ([1,2,3,4,5]) [1,2,3,4,5]

Tuppel Sequenzen mit fester Länge Die Elemente können unterschiedliche Typen haben Vergleichbar mit C-structs oder Pascalrecords (False, True) ( Jan, Hermanns, 29) ((1, a ), [1, 2, 3]) ([(1, a ), (2, b )], 4711, foo ) 31

Mit Hilfe von Tuppeln und dem Schlüsselwort type kann man eigene Datenstrukturen definieren. type Name = String type Age = Int type Person = (Name, Age) createperson :: Name -> Age -> Person createperson n a = (n, a) getage :: Person -> Age getage (_, a) = a getname :: Person -> Name getname (n, _) = n 32

Für Paare (2-Tuppel) und Trippel (3-Tuppel) gibt es ein paar vordefinierte Funktionen. Daher könnte man die Definitionen: getage :: Person -> Age getage (_, a) = a getname :: Person -> Name getname (n, _) = n wie folgt vereinfachen: getage :: Person -> Age getage p = snd p getname :: Person -> Name getname p = fst p 33

List Comprehensions In Anlehnung an die Schreibweise aus der Mengenlehre, {x 2 x {1 } } können Listen auch in Haskell definiert werden. [x^2 x <- [1..]] [1,4,9,16,25,36,49,64,81,usw.] [(x, y) x <- [1..3], y <- [1..2]] [(1,1),(1,2),(2,1),(2,2),(3,1),(3,2)] [(x, y) x <- [1..3], y <- [1..x]] [(1,1),(2,1),(2,2),(3,1),(3,2),(3,3)] 34

Innerhalb einer List Comprehension können tests definiert werden. [x x <- [2,4..10]] [2,4,6,8,10] [x x <- [1..10], even x] [2,4,6,8,10] [x x <- [1..10], even x, x>3] [4,6,8,10] Auf Basis der bereits definierten Funktionen: getadults :: [Person] -> [Person] getadults ps = [p p <- ps, isadult (getage p)] 35

Quicksort revisited qs [] = [] qs (x:xs) = qs lessx ++ [x] ++ qs greatereqx where lessx = [e e<-xs, e < x] greatereqx = [e e<-xs, e >= x] Folgende Eigenschaften sollten klar sein: qs[] [] qs[4] qs[] ++ [4] ++ qs[] [] ++ [4] ++ [] [4] qs[4711] [4711] 36

qs [] = [] qs (x:xs) = qs lessx ++ [x] ++ qs greatereqx where lessx = [e e<-xs, e < x] greatereqx = [e e<-xs, e >= x] qs[5,6,3,5,2,8,9] qs[3,2] ++ [5] ++ qs[6,5,8,9] qs[2] ++ [3] ++ qs[] qs[5] ++ [6] ++ qs[8,9] [2] ++ [3] ++ [] [5] ++ [6] ++ qs[8,9] [2,3] [5,6] ++ qs[8,9] qs[] ++ [8] ++ qs[9] [] ++ [8] ++ [9] [8,9] [2,3] ++ [5] ++ [5,6] ++ [8,9] [2,3,5,5,6,8,9] 37

Higher-order functions Funktionen können als Daten-Objekte an andere Funktion übergeben oder als Werte zurückgeliefert werden. map :: (a -> b) -> [a] -> [b] map f xs = [ f x x <- xs ] double double x :: Int -> Int = 2 * x doubleall :: [Int] -> [Int] doubleall xs = map double xs 38

Lambda Ausdrücke Mit Hilfe von λ -Ausdrücken können anonyme Funktionen erzeugt werden. doubleall doubleall xs :: [Int] -> [Int] = map (\x -> x*2) xs λ -Ausdrücke können auch mehrere Parameter haben. applytoboth :: (a -> a -> a) -> a -> a applytoboth f x = f x x applytoboth (\x y -> x+y) 5 10 39

Listen kumulieren foldr1 :: (a -> a -> a) -> [a] -> a (1) foldr1 f [x] = x (2) foldr1 f (x:xs) = f x (foldr1 f xs) foldr1 (+) [1..4] (2) (+) 1 (foldr1 (+) [2,3,4]) (2) (+) 1 ((+) 2 (foldr1 (+) [3,4])) (2) (+) 1 ((+) 2 ((+) 3 (foldr1 (+) [4]))) (1) (+) 1 ((+) 2 ((+) 3 (4))) (+) 1 ((+) 2 (7)) (+) 1 (9) 10 sumup n = foldr1 (+) [0..n] 40

foldr1 funktioniert nur für Listen mit mindestens einem Element. foldr :: (a -> b -> b) -> b -> [a] -> b (1) foldr f z [] = z (2) foldr f z (x:xs) = f x (foldr f z xs) len len xs :: [a] -> Int = foldr (\_ n -> n+1) 0 xs! len Jan foldr (\_ n -> n+1) 0 [ J, a, n ]! (2) λ J (foldr λ 0 [ a, n ])!! (2) λ J (λ a (foldr λ 0 [ n ])) (2) λ J (λ a (λ n (foldr λ 0 []))) (1) λ J (λ a ((\_ n -> n+1) n 0)) λ J ((\_ n -> n+1) a 1) (\_ n -> n+1) J 2 3 41

foldr tauscht den cons Operator durch die übergebene Funktion aus und die leere Liste durch das initiale Element. sum :: [Int] -> Int sum xs = foldr (+) 0 xs sum [8,2,5] 8 : 2 : 5 : [] 8 : 2 : 5 : 0 8 + 2 + 5 + 0 8 + (2 + (5 + 0)) 42

Durch die Verwendung von Higher-order functions kann man Definitionen sehr abstrakt formulieren. overallage :: [Person] -> Int overallage ps = foldr (+) 0 (map getage ps) 43

Partielle Auswertung Das -> Symbol ist rechts-assoziativ, so dass die Typdeklarationen f :: a -> b -> c g :: a -> b -> c -> d h :: a -> b -> c -> d -> e interpretiert werden als f :: a -> (b -> c) g :: a -> (b -> (c -> d)) h :: a -> (b -> (c -> (d -> e))) Funktionen liegen implizit in curried Form vor. 44

Die Anwendung einer Funktion auf ihre Argumente ist links-assoziativ. mul :: Int -> Int -> Int mul x y = x * y mul 3 5 Die Anwendung passiert daher schrittweise von links nach rechts. (mul 3) 5 45

Beispiele Die folgenden Funktionen mul map :: Int -> Int -> Int :: (a -> b) -> [a] -> [b] foldr :: (a -> b -> b) -> b -> [a] -> b haben die impliziten Typen mul map :: Int -> (Int -> Int) :: (a -> b) -> ([a] -> [b]) foldr :: (a -> (b -> b)) -> (b -> ([a] -> b)) 46

Übergibt man einer Funktion weniger Parameter als vorgesehen, so erhält man eine partiell ausgewertete Funktion zurück. mul mul x y :: Int -> (Int -> Int) = x * y double :: Int -> Int double = mul 2 double 4 8 Partiell ausgewertete Funktionen können ganz normal als Daten übergeben werden. doubleall :: [Int] -> [Int] doubleall = map (mul 2) 47

Der implizite Typ von foldr. foldr :: (a -> b -> b) -> b -> [a] -> b foldr :: (a -> b -> b) -> (b -> ([a] -> b)) foldr :: (a -> (b -> b)) -> (b -> ([a] -> b)) Das Currying funktioniert auch mit mehreren Parametern. concat :: [[a]] -> [a] concat = foldr (++) [] and, or and or :: [Bool] -> Bool = foldr (&&) True = foldr ( ) False 48

Operator sections Partielle Auswertung funktioniert natürlich auch bei Operatoren. (op x) y = y op x (x op) y = x op y Beispiele: (+2) -- addiert 2 zum Argument (2+) -- addiert 2 zum Argument (>2) -- prueft, ob Argument groesser 2 (3:) -- haengt 3 an den Kopf einer Liste (++ \n )! -- Newline am Ende des Strings ( \n ++) -- Newline am Anfang des Strings doubleall = map (2*) 49

Schlussbemerkungen Haskell hat noch wesentlich mehr zu bieten Information-Hiding (Module) algebraische Datentypen einschränkenden Polymorphismus (Typklassen) ein interessantes I/O-Konzept (Monaden) Weitere Informationen finden Sie unter: http://www.haskell.org Sehr empfehlenswert ist das Buch:! Haskell - The Craft of Functional Programming von Simon Thompson ISBN 0-201-34275-8 50