Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen...

35
Algorithmen und Datenstrukturen II Peter Steffen AG Praktische Informatik Technische Fakult¨ at Universit¨ at Bielefeld Vorlesung Sommer 2009 Peter Steffen Universit¨ at Bielefeld A&D II, Vorlesung 2009

Transcript of Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen...

Page 1: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Algorithmen und Datenstrukturen II

Peter Steffen

AG Praktische InformatikTechnische FakultatUniversitat Bielefeld

Vorlesung Sommer 2009

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 2: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Teil I

Ubergang von funktionaler zu OOP

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 3: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Imperative vs. funktionale Programmierung

Plakativ lassen sich folgende Aussagen treffen:

funktional: Berechnung von Werten von Ausdruckenimperativ: Berechnung des Kontrollflusses

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 4: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Beispiele zur Unterscheidung: Java vs. Haskell (I)

Beispiel (Berechnung des Betrages einer ganzen Zahl n)

public static int abs(int n) {if (n >= 0)return n;

elsereturn -n;

}

> abs’ :: (Ord a, Num a) => a -> a> abs’ n | n >= 0 = n> | otherwise = -n

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 5: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Beispiele zur Unterscheidung: Java vs. Haskell (II)

Beispiel (Berechnung von sum(n) =n∑

i=1

i2)

public static int sum(int n) {

int s = 0;

for(int i=1; i<=n; i++)

s = s + i * i;

return s;

}

> sum’ :: (Enum a, Num a) => a -> a

> sum’ n = foldl g 0 [1..n]

> where g x y = x + y * y

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 6: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Beispiele zur Unterscheidung: Java vs. Haskell (II)

Beispiel (Berechnung vonnextSquare(n) = min{q | q > n, q = s2, s ∈ N})

public static int nextSquare(int n) {

int i = 1;

int q = 1;

while (q <= n) {

i++;

q = i*i;

}

return q;

}

> nextSquare’ :: (Num a, Enum a) => a -> a

> nextSquare’ n = (head.dropWhile (<=n).map (^2)) [1..]

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 7: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Entsprechungen/Unterschiede

funktional imperativ

Liste vonZwischenergebnissen(anonym)

Rekursionsschemata(foldl, map)

abstrahiert vonZwischenergebnissen

Speicheraufwandig

Listen spielen eine zentraleRolle

Wertabfolgen in Behaltern(benannt)

spezielle Anweisungen(while, for)

Behalter werdenweiterbenutzt

Speicherokonomisch

Listen sind ein Datentypwie viele andere

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 8: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Beispiel (Listen in Java)

public class Node {

protected int element;

protected Node next;

public Node(int val, Node node) {

element = val;

next = node;

}

public int element() {

return element;

}

public Node next() {

return next;

}

}

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 9: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Knoten zu Listen verknupfen

[1,2] =1s �- 2s �

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 10: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Die Konstruktoren von IntList

Beispiel (Konstruktur IntList)

public class IntList {private Node first = null;

public IntList() { }

public IntList(Node first) {this.first = first;

}}

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 11: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

public IntList ()

first�public IntList (Node first)

first�- 1r ��- 2r ��- · · ·r ��- nr ��Beispiel (Methode emtpy testet, ob Liste leer ist)

public boolean empty() {return first == null;

}

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 12: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Die Methode cons

Beispiel

/** cons builds up lists. Returns a new reference to the list

cons(val,xs), does not change xs. In order to emphasize that cons

doesn’t change the list it acts upon, it is declared static. */

public static IntList cons(int val, IntList xs) {

Node n = new Node(val, xs.first);

return new IntList(n);

}

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 13: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Cons-Beispiel

cons(x,xs) wobei in (a) xs leer ist und in (b) xs der Liste [2,3]entspricht.

(a)

(b)

xs.first� return value�- xr ��xs.first�

xs.first�- 2r ��- 3r ��return value�- xr ��-

xs.first�- 2r ��- 3r ��

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 14: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Die Methoden head und tail

Die Funktionen head und tail sind in Haskell folgendermaßendefiniert:

head (x:xs) = x tail (x:xs) = xs

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 15: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Beispiel

/** Returns the first element of a list. Returns -1 and prints an

error message if the list is empty; does not change the list. */

public int head() {

if (empty()) {

System.out.println("Error at method head(): Empty List");

return -1; // an exception would be better

}

return first.element();

}

/** Returns a new reference to the list obtained by removing the

first element. Returns null and prints an error message if the

list is empty; does not change the list. */

public IntList tail() {

if (empty()) {

System.out.println("Error at method tail(): Empty List");

return null; // an exception would be better

}

return new IntList(first.next());

}

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 16: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Die Methode append

Die Definition von append lautet in Haskell:

append [] ys = ysappend (x:xs) ys = x:append xs ys

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 17: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Append rekursiv

Beispiel (append rekursiv)

/** Returns a new reference to the list obtained by concatenation

of xs and ys; does not change the lists. In order to

emphasize this, it is declared static. */

public static IntList append(IntList xs,IntList ys) {

if (xs.empty())

return ys;

else

return cons(xs.head(),append(xs.tail(),ys));

}

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 18: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

... und nicht-rekursiv

Beispiel (append nicht-rekursiv)

private static IntList append2(IntList xs,IntList ys) {

Node tmp;

if (xs.empty())

return ys;

else {

for(tmp=xs.first; tmp.next!=null; tmp=tmp.next)

; // Find last node

tmp.next = ys.first;

return xs;

}

}

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 19: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Append-Beispiel

xs.first�- 1q ��- 2q �� ys.first�- 3q ��- 4q ��- 5q ��zs = append(xs,ys) bzw. zs = append2(xs,ys)

��

@@

@R

append (rekursiv)(nicht desktruktive Variante)

append2 (nicht rekursiv)(desktruktive Variante)

xs.first�- 1q ��- 2q ��zs.first�- 1q ��- 2q ��-

ys.first�- 3q ��- 4q ��- 5q ��xs.first�-zs.first

�- 1q ��- 2q ��-ys.first�- 3q ��- 4q ��- 5q ��

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 20: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Seiteneffekte!

Das Verhalten von append2 ist destruktiv, denn beim Verkettenvon xs und ys wird xs zerstort (oder milder ausgedruckt,verandert). Diesen Seiteneffekt muss man bei jeder Anwendungvon append2 berucksichtigen! Aber auch die erste Version birgteine Gefahr: Wenn nach zs = append(xs,ys) die Liste ysverandert wird, verandert sich damit auch zs.

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 21: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Sonderfall xs = ys

xs.first�- 1q ��- 2q ��zs = append(xs,xs) bzw. zs = append2(xs,xs)

���

@@@R

append append2

zs.first�- 1q ��- 2q ��-xs.first�- 1q ��- 2q �� xs.first�-

zs.first

�- 1q ��- 2q � 6

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 22: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Vergleich zwischen Haskell und Java

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 23: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Parametrischer Typpolymorphismus

Die Haskell-Funktion swap ist definiert durch:

Definition

swap :: (a,b) -> (b,a)swap (x,y) = (y,x)

Beispielsweise ist (1,"a") das Ergebnis von swap("a",1).

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 24: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Um diese Funktion in Java zu implementieren, benutzen wir den Typ Object.

Beispiel

public class Pair {

protected Object x;

protected Object y;

public Pair(Object x, Object y) {

this.x = x;

this.y = y;

}

public void swap() {

Object tmp = x;

x = y;

y = tmp;

}

public static void main(String[] args) {

Pair p = new Pair("a",new Integer(1));

p.swap();

System.out.println(((Integer)(p.x)).intValue()+(String)p.y);

}

}

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 25: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Da elementare Daten keine Objekte sind, mussen sie in Objekteverwandelt werden. Dies geschieht mit Hilfe der Hullenklassen –elementare Daten werden durch einen Hullenklassenkonstruktor“eingehullt”und damit zu Objekten.

Object��

��� ?

HHHHj

Boolean Char NumberPPPPPPq

@@R

��

������)LongIntegerDoubleFloat

Abbildung: Klassenhierarchie der Hullenklassen

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 26: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

IntPair

Beispiel

public class IntPair {

protected int x;

protected int y;

public IntPair(int x, int y) {

this.x = x;

this.y = y;

}

public void swap() {

int tmp = x;

x = y;

y = tmp;

}

}

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 27: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Generic Types

Seit Java 5 konnen Klassen mit Typparametern definiertwerden.

Solche Klassen werden Generische Klassen oderParametrisierte Klassen genannt.

Der Typparameter wird in ’<>’ nach dem Klassennamenangegeben.

Generische Klassen werden wie andere Klassen auch benutzt,jedoch muss bei der Instanziierung der Typ angegeben werden

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 28: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Beispiel (Generic Types)

class Pair<E> {

protected E x;

protected E y;

public Pair(E x, E y) {

this.x = x;

this.y = y;

}

public void swap() {

E tmp = x;

x = y;

y = tmp;

}

public static void main(String[] args) {

Pair<Integer> intPair = new Pair<Integer>(1,2);

Pair<String> charPair = new Pair<String>("a","b");

intPair.swap();

charPair.swap();

System.out.println(intPair.x + "," + intPair.y);

System.out.println(charPair.x + "," + charPair.y);

}

}Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 29: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Funktionen hoherer Ordnung

In Haskell gibt es keinen Unterschied zwischen Funktionen undDaten: Funktionen konnen Argumente anderer Funktionen sein,Funktionen konnen Funktionen als Wert liefern etc. In Java sindFunktionen (Methoden) Bestandteil von Objekten. Da FunktionenObjekte als Argumente oder Ruckgabewert haben konnen,unterstutzt Java insofern Funktionen hoherer Ordnung.

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 30: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Klassen, Objekte und Vererbung

in Java kein Problem (objektorientierte Programmiersprache);

Haskell-Klassen definieren abstrakte Methoden, jedoch keineObjekte. Eine Instanz einer Klasse muss diese abstraktenMethoden implementieren (d.h. eine eigene Definitionangeben). Insofern entspricht eine Haskell-Klasse grobgesprochen einer abstrakten Klasse in Java, die nur abstrakteMethoden enthalt (genauer einer Schnittstelle).

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 31: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Keine Entsprechung gibt es z.B.

in Java fur die unendlichen Datenstrukturen in Haskell

in Haskell fur die von Java unterstutzte Nebenlaufigkeit

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 32: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Algebraische Datentypen und Pattern Matching (I)

Pattern Matching kann nach einer Idee von Odersky & Wadler(1997) auf sehr elegante Art und Weise simuliert werden. Wirdemonstrieren dies an Hand der append-Funktion auf Listen.

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 33: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Algebraische Datentypen und Pattern Matching (II)

Beispiel

public class List {

protected static final int NIL_TAG = 0;

protected static final int CONS_TAG = 1;

protected int tag;

public List append(List ys) {

switch (this.tag) {

case NIL_TAG:

return ys;

case CONS_TAG:

char x = ((Cons)this).head;

List xs = ((Cons)this).tail;

return new Cons(x, xs.append(ys));

default:

return new Nil(); //an exception would be better

}

}

}

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 34: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

Algebraische Datentypen und Pattern Matching (III)

Beispiel

public class Cons extends List {

protected char head;

protected List tail;

public Cons(char head, List tail) {

this.tag = CONS_TAG;

this.head = head;

this.tail = tail;

}

}

public class Nil extends List {

public Nil() {

this.tag = NIL_TAG;

}

}

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009

Page 35: Algorithmen und Datenstrukturen II · Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java Append rekursiv Beispiel (append rekursiv) /** Returns a new reference

Imperative vs. funktionale Programmierung Vergleich zwischen Haskell und Java

K. Arnold, J. Gosling: JavaTM - Die Programmiersprache.Addison-Wesley, 1996.

T.H. Cormen, C.E. Leierson, R.L. Rivest: Introduction toAlgorithms. MIT Press, 1990.

D. Flanagan: Java in a Nutshell. O’Reilly & Associates Inc.,1996.

F. Jobst: Programmieren in Java. Hanser Verlag, 1996.

H. Klaeren: Vom Problem zum Programm. 2.Auflage,B.G. Teubner Verlag, 1991.

K. Echtle, M. Goedicke: Lehrbuch der Programmierung mitJava. dpunkt-Verlag, 2000.

Peter Steffen Universitat Bielefeld

A&D II, Vorlesung 2009