Rückblick und Ausblick

Werbung
Paradigmen zur Algorithmenbeschreibung
In einem objektorientierten Algorithmus werden Datenstrukturen und Methoden zu
einer Klasse zusammengefasst. Von jeder Klasse können Objekte gemäß der
Datenstruktur erstellt und über die Methoden manipuliert werden.
In einem imperativen Algorithmus gibt es Variable, die verschiedene Werte annehmen
können. Die Menge aller Variablen und ihrer Werte sowie der Programmzähler
beschreiben den Zustand zu einem bestimmten Zeitpunkt. Ein Algorithmus bewirkt
eine Zustandstransformation.
Ein Algorithmus heißt funktional, wenn die zugrunde liegende Berechnungsvorschrift
mittels einer Sammlung von Funktionen definiert wird. Die Funktionsdefinitionen
dürfen insbesondere Rekursionen und Funktionen höherer Ordnung enthalten.
Ein logischer (deduktiver) Algorithmus führt Berechnungen durch, indem er aus
Fakten und Regeln durch Ableitungen in einem logischem Kalkül Ziele beweist.
Rückblick und Ausblick
A-1
Algorithmus von Euklid
Der folgende, in einer imperativen Programmiersprache formulierte
Algorithmus von Euklid
berechnet den größten gemeinsamen Teiler der Zahlen x , y ∈ N mit x ≥ 0 und y > 0:
a := x;
b := y;
while b
do r :=
a :=
b :=
od
Rückblick und Ausblick
# 0
a mod b;
b;
r
A-2
Algorithmus von Euklid
Variable
r
a
b
z2
–
36
52
z5
36
52
36
z8
16
36
16
z11
4
16
4
z14
0
4
0
ggT(36, 52) = 4
Durchlaufene Zustände:
z0, z1, z2, ... , z14
Zustandstransformation:
z0 7−→ z14
Rückblick und Ausblick
A-3
Imperatives Programmieren
• In einem imperativen Programm gibt es Variable, die Werte speichern können. Die
Variablen und ihre Werte legen den Zustand des Programms fest. Der Zustand
ändert sich mit dem Ablauf des Programms.
• Die Wertzuweisung gestattet es, den Zustand zu verändern.
• ◦ Mit einer Sequenz können Anweisungen nacheinander ausgeführt werden.
◦ Die Selektion erlaubt die Auswahl zwischen Anweisungen.
◦ Anweisungen können mit der Iteration wiederholt werden.
• ◦ Eingabe-Anweisungen ermöglichen es, den Zustand von außen zu beeinflussen.
◦ Ausgabe-Anweisungen erstellen einen Ausdruck des Zustands (oder eines Teils
davon).
Rückblick und Ausblick
A-4
Imperatives Programmieren
• Prozeduren: Abstraktionen von Anweisungen
• Funktionen: Abstraktionen von Ausdrücken
• Datentypen:
◦ Primitive Datentypen:
boolean, char, int, real
◦ Zusammengesetzte Datentypen:
enumeration, array, record, pointer
◦ Typdeklarationen: Abstraktionen von Datentypen
Typsysteme können unabhängig von Paradigmen und Sprachen definiert und
untersucht werden.
Rückblick und Ausblick
A-5
Imperatives Programmieren
• Weitere Kontrollstrukturen
• Module
• Ausnahmebehandlung
• Parallelverarbeitung
Rückblick und Ausblick
A-6
Algorithmus von Euklid
• imperative/iterative Formulierung:
while b #
do r :=
a :=
b :=
od
0
a mod b;
b;
r
• funktionale/rekursive Formulierung:
(
a
b=0
ggT(a,b) =
ggT(b, a mod b) b =
6 0
Rückblick und Ausblick
A-7
Algorithmus von Euklid
(Scheme, funktional)
(define (ggT a b)
(if (= b 0)
a
(ggT b (remainder a b))))
(ggt 36 52)
> 4
Rückblick und Ausblick
A-8
Funktionales Programmieren
• Ein funktionaler Algorithmus formuliert die Berechnungsvorschrift durch eine
Menge von Funktionen.
• Die Funktionen können wechselseitig-rekursiv oder auch
• von höherer Ordnung (Funktionale) sein.
Rückblick und Ausblick
A-9
Funktionen höherer Ordnung
(define (inc n) (+ n 1))
(define (square x) (* x x))
(define (cube x) (* x x x))
(define (sum f a next b)
(if (> a b)
0
(+ (f a)
(sum f (next a) next b))))
Rückblick und Ausblick
A-10
(define (sum-square a b)
(sum square a inc b))
(define (sum-cube a b)
(sum cube a inc b))
> (sum-square 1 4)
30
> (sum-cube 1 4)
100
Rückblick und Ausblick
A-11
Deduktive Algorithmen
• Ein deduktiver (logischer) Algorithmus führt Berechnungen durch, indem er aus
Fakten und Regeln weitere Fakten, sogenannte Anfragen (Ziele), beweist.
• Fakten:
P
• Regeln:
P if Q1 and Q2 and ... and Qk
Regeln dieser Form werden auch Horn-Klauseln genannt. Fakten können als Regeln
mit k = 0 gesehen werden.
• Ein logisches Programm ist eine endliche Menge von Fakten und Regeln. Die
folgenden Beispiele wurden in der deduktiven Programmiersprache Prolog
geschrieben.
Rückblick und Ausblick
A-12
Beispiel: Eingabe der Fakten und Regeln
vater(johann,heinrich).
vater(johann,thomas).
vater(heinrich,carla).
vater(thomas,erika).
vater(thomas,klaus).
vater(thomas,golo).
vater(thomas,monika).
vater(thomas,elisabeth).
vater(thomas,michael).
verheiratet(johann,julia).
verheiratet(heinrich,maria).
verheiratet(thomas,katia).
mutter(X,Y) :- vater(Z,Y), verheiratet(Z,X).
geschwister(X,Y) :- vater(Z,X), vater(Z,Y), X = / = Y.
Rückblick und Ausblick
A-13
Beispiel: Eingabe der Anfragen
Nachdem das Programm eingelesen wurde, können Anfragen gestellt werden, die von
einer Interferenzmaschine, zum Beispiel einem Prolog-Interpreter, beantwortet werden.
Anfragen werden nach der Eingabeaufforderung | ?- gestellt:
| ?- geschwister(thomas, heinrich).
true ? ;
no
| ?- geschwister(thomas, golo).
no
Die Ausgabe true bedeutet, dass die Anfrage positiv beantwortet wurde, das heißt,
dass Thomas und Heinrich Geschwister sind. Nach einem Fragezeichen erwartet der
Interpreter Anweisungen, wie fortzufahren ist. Ein Semikolon ist die Aufforderung,
nach weiteren Lösungen zu suchen.
Rückblick und Ausblick
A-14
Beispiel: Eingabe der Anfragen
Falls eine Anfrage eine Variable enthält, werden alle Belegungen für die Variablen
ermittelt, die die Aussage wahr werden lassen. Wenn wir die Geschwister von Golo
suchen, stellen wir die folgende Anfrage.
| ?- geschwister(X,golo).
X = erika ? ;
X = klaus ? ;
X = monika ? ;
X = elisabeth ? ;
X = michael ? ;
no
Erika, Klaus, Monika, Elisabeth und Michael sind also die Geschwister von Golo.
Rückblick und Ausblick
A-15
Beispiel: Eingabe der Anfragen
Eine Anfrage kann mehr als eine Variable enthalten. Durch
| ?- geschwister(X,Y).
werden insgesamt 32 Geschwisterpaare ermittelt, da Paare wegen der Symmetrie der
Relation doppelt ausgegeben werden.
Rückblick und Ausblick
A-16
Algorithmus von Euklid
(Prolog, deduktiv)
ggt(A,0,A).
ggt(A,B,Z) :- U is A mod B, ggt(B,U,Z).
| ?- ggt(36,52,Z).
Z = 4 ?
Rückblick und Ausblick
A-17
Funktionen und Relationen
• Eine Funktion f : X −→ Y ordnet jedem Element der Menge X
(Definitionsbereich) genau ein Element der Menge Y (Wertebereich) zu:
x 7−→ f (x )
• Eine Relation R ⊆ X × Y besteht aus Paaren (x , y ) ∈ X × Y . Dabei kann es zu
einem x ∈ X mehrere Elemente y ∈ Y mit
(x , y ) ∈ R
geben.
Rückblick und Ausblick
A-18
Deduktives Programmieren
• Deduktives Programmieren beschäftigt sich mit Relationen. Funktionen sind ja
spezielle Relationen.
• Fakten und Regeln können als Eingabe von Relationen bzw. als
Konstruktionsvorschriften für Relationen angesehen werden.
• Anfragen überprüfen, ob Paare in einer bestimmten Relation stehen oder ermitteln
solche Paare:
◦ Eine Anfrage der Form P(x , y ) überprüft, ob x und y bezüglich P in Relation
stehen.
◦ Die Anfrage P(X , y ) berechnet alle x mit (x , y ) ∈ P.
◦ Anfragen der Form P(X , Y ) führen zur Ausgabe aller Paare (x , y ) mit
(x , y ) ∈ P.
Rückblick und Ausblick
A-19
Deklaratives Programmieren
• In deklarativen Programmiersprachen wird aus einer nach bestimmten Regeln
gebildeten mathematischen Formulierung eines Problems automatisch ein
Programm erzeugt.
• Die formale Problembeschreibung kann z. B. auf der Prädikatenlogik (logische
Programmiersprachen) oder dem λ-Kalkül (funktionale Programmiersprachen)
basieren.
• Deklarative Programmiersprachen haben sich vom Konzept der ausführenden
Maschine gelöst.
Rückblick und Ausblick
A-20
Entwicklung der Programmiersprachen
.
.
2000
C#
1995
Programmiersprachen in der
Informatikausbildung
JAVA
SCHEME (standard)
1990
• Algol
OCCAM
C++
1985
CSP
ADA
1980
SMALLTALK80
MODULA−2
1975 C
SCHEME
PROLOG
PASCAL
1970
ALGOL68
• Algol68
• Modula-2
LOGO
SIMULA
• Scheme
1965 PL/I
BASIC
1960
1955
COBOL
ALGOL
FORTRAN
LISP
• Java
.
Rückblick und Ausblick
A-21
Programmiersprachen
• Imperative Programmiersprachen:
Cobol, Fortran, PL/I, Basic, Algol, Algol68, Pascal, Modula-2, C, Ada
• Funktionale Programmiersprachen:
Lisp, Scheme, ML, Haskell, Scala. Die Sprache Scala ist eine Erweiterung von Java.
• Objektorientierte Programmiersprachen:
C++, Eiffel, Smalltalk, Java, C#, Oberon
• Logische Programmiersprachen:
Prolog
• Skriptsprachen, Spezialsprachen
Rückblick und Ausblick
A-22
Bisherige Entwicklung von Java
1992–1995
Jan.
Anfang
Dez.
Jan.
Mai
Februar
Ende
Dezember
Juli
März
1996
1997
1998
1999
2000
2002
2004
2006
2011
2014
Java-Vorläufer, zuerst unter dem Namen „Oak“.
Neu: Applets (little applications)
JDK 1.0 (Java Development Kit)
JDK 1.1
JDK 1.2, wurde
umbenannt in „Java 2 Plattform“
Java 2, JDK 1.3
Java 2, JDK 1.4
Java 2, JDK 5.0 (interne Versionsnummer: 1.5.0) „Tiger“
Java Standard Edition 6 („Mustang“)
Java Standard Edition 7 („Dolphin“)
Java Standard Edition 8
Eigentlich sollte Java 8 im September 2013 veröffentlicht werden.
Rückblick und Ausblick
A-23
Fragestellung: Statischer/dynamischer Scope
Wie lautet die Ausgabe des folgenden Programms?
public class Test {
static int x=7;
static void p() {x=0;}
// x ist eine globale Variable.
public static void main(String[] args) {
int x=5;
p();
System.out.println(x);
}
}
• Statischer Scope: Ausgabe: 5, Dynamischer Scope: Ausgabe: 0.
• Die Semantik der Methode p hängt also davon ab, wie die globale Variable x genommen wird.
• Wir wissen: Java gibt die 5 aus.
Rückblick und Ausblick
A-24
Java 8
• Die wichtigste Erweiterung ist das Projekt Lambda. Das Ziel dieses Projektes ist
die Einführung von Closures. Damit wird die Bedeutung von globalen Variablen
definiert. Globale Variable können vielfältiger als das obige Beispiel sein.
• Funktionale Schnittstellen sind Schnittstellen, die genau eine abstrakte Methode
enthalten. Abstrakte Klassen mit einer abstrakten Methode zählt man nicht zu den
funktionalen Schnittstellen. Schnittstellen sollen auch statische Methoden
enthalten können.
• Eine wichtige Erweiterung sind Lambda-Ausdrücke. Ein Lambda-Ausdruck ist ein
Literal, das eine funktionale Schnittstelle implementiert, ohne der Funktion einen
Namen zu geben.
• Beispiele für Lambda-Ausdrücke, Funktionale Schnittstellen, default-Methoden, ...
haben wir schon gesehen
Rückblick und Ausblick
A-25
Java 8
Auf den nächsten Folien steht etwas zur Wiederholung von Java 8.
Rückblick und Ausblick
A-26
Lambda-Ausdrücke und funktionale Interfaces
Ein Funktionales Interface ist ein normales Interface, das aber nur eine einzige
abstrakte Methode enthält.
Grundlage der Lambda-Ausdrücke sind funktionale Interfaces. Lambda-Ausdrücke
bestehen aus einer Parameterliste und dem Rumpf einer Methode, die durch ->
verbunden sind.
So können die Lambda-Ausdrücke aussehen:
(Liste der Parameter) -> { Befehl; ...; Befehl; }
(Liste der Parameter) -> Ausdruck;
Die Liste der Parameter kann evtl. auch leer sein.
Rückblick und Ausblick
A-27
Lambda-Ausdruck und funktionales Interface: Beispiel
interface Funktion {
double wurzel (double y);
}
public class Lambda {
public static void main(String[] args) {
Funktion f = (y) -> Math.sqrt(y);
// Lambda-Ausdruck
for (double x=0.0; x<=5.0; x++) {
double r = f.wurzel(x);
System.out.printf("Wurzel von %4.2f: %6.5f%n",x,r);
}
}
}
Rückblick und Ausblick
A-28
Ausgabe:
Wurzel
Wurzel
Wurzel
Wurzel
Wurzel
Wurzel
von
von
von
von
von
von
0.00:
1.00:
2.00:
3.00:
4.00:
5.00:
Rückblick und Ausblick
0.00000
1.00000
1.41421
1.73205
2.00000
2.23607
A-29
Interfaces mit Default- und statischen Methoden
Eine Default-Methode ermöglicht es, eine Standardimplementierung in einem Interface
zu definieren. Diese Methode muss das Schlüsselwort default bekommen.
Eine Standardimplementierung einer Interface-Methode kann auch eine static
Methode werden. Diese Methode kann auch schon dann verwendet werden, wenn es
noch kein Objekt der Klasse, die das Interface implementiert, gibt.
Rückblick und Ausblick
A-30
Interface mit Default-Methode: Beispiel
interface Funktion {
double wurzel (double y);
default double quadrat (double x) {return x*x;}
}
public class Formel implements Funktion {
public double wurzel (double y) {return Math.sqrt(y);}
public static void main(String[] args) {
Formel f = new Formel();
for (double x=0.0; x<=5.0; x++) {
double r = f.wurzel(x);
System.out.printf("Wurzel von %4.2f: %6.5f%n",x,r);
r = f.quadrat(x);
System.out.printf("Quadrat von %4.2f: %6.5f%n",x,r);
}
}
}
Rückblick und Ausblick
A-31
Interface mit statischer Methode: Beispiel
interface Funktion {
double wurzel (double y);
static double hochdrei (double x) {return x*x*x;}
}
public class Test implements Funktion {
public double wurzel (double y) {return Math.sqrt(y);}
public static void main(String[] args) {
for (double x=0.0; x<=5.0; x++) {
double r = Funktion.hochdrei(x);
System.out.printf("Quadrat von %4.2f: %8.3f%n",x,r);
// Für die statische Methode muss es kein Objekt geben!
}
}
}
Rückblick und Ausblick
A-32
Funktionen als Parameter: Beispiel
interface Funktion {
int rechne (int x, int y);
}
public class Test {
public static void anzeigen(Funktion f, Funktion g) {
for (int i=0; i<=10; i+=1) {
int j = f.rechne(i,i)+g.rechne(i,i);
System.out.printf("%4d -> %4d%n",i,j);
}
}
public static void main(String[] args) {
// Ausgabe des 5-fachen Wertes
anzeigen((int x,int y)->{y=3;return x*y;},(int x,int y)->{return x+y;});
System.out.println();
}
}
Rückblick und Ausblick
A-33
Funktionale Programmierung
Wie angekündigt haben wir also aus Java 8 Beispiele für
• Lambda-Ausdrücke,
• Funktionale Interfaces und
• Interfaces mit Default-Methoden und statischen Methoden
gesehen. Den Aspekt
• Streams und Pipeline-Operationen
werden wir später sehen.
Rückblick und Ausblick
A-34
Closures
Friedrich Esser:
Ein Closure ist ein Block (bzw. eine Einheit) von Code, der freie Variable aus der
Umgebung, genauer dem umgebenden Scope zur Berechnung des Ergebnisses mit
einbezieht. Abhängig von der Art der freien Variablen, gibt es Closures, deren
– Ergebnisse nur von ihren Argumenten abhängen, da die freien Variablen immutable
sind.
– Ergebnisse mit den mutablen Werten der freien Variablen variieren.
Leider wird Closure je nach Autor oder Sprache evtl. anders interpretiert.
Rückblick und Ausblick
A-35
Scala
• Scala ist eine hybride Sprache: imperativ, objektorientiert, funktional.
• SCAlable LAnguage
• Scala wird in der Schweiz entwickelt. Leiter: Martin Odersky.
• Scala-Programme können Java-Archive (jars) verwenden und umgekehrt.
Rückblick und Ausblick
A-36
Ist Java 8 der Todesstoß für Scala?
Will Java 8 kill Scala?
Wir erinnern uns alle noch zu gut: Als Scala damals vorgestellt wurde und die
Entwickler-Gemeinde Gefallen an der Sprache fand, unkte man schon, Scala würde
Java bald beerben. Und dabei war Scala nicht die einzige JVM-Sprache, die als
»Java-Killer« bezeichnet wurde (siehe z.B. Ceylon).
Jetzt scheint sich der Spieß allerdings umzudrehen, denn mit Java 8 hat die
Programmiersprache dank Lambda-Expressions, Methodenreferenzen, Functional
Interfaces und Co. einen enormen Sprung in Richtung mehr Produktivität und
Leistungsfähigkeit gemacht. Und schon fragen sich Entwickler wie Ahmed Soliman in
seinem Blog: Will Java 8 kill Scala? Oder rücken die beiden Sprachen nicht eher näher
zusammen?
(Claudia Fröhling, 27. März 2014)
Rückblick und Ausblick
A-37
Anmerkungen zur Objektorientierung (Wiederholung)
Das objektorientierte Paradigma kann anders (und/oder erweitert) als in Java
angeboten werden:
• keine primitiven Datentypen
• keine statischen Attribute, keine statischen Methoden
• singleton object, standalone object, case class
• companion object, companion class
• Mehrfachvererbung
• mixin, trait
• ...
Rückblick und Ausblick
A-38
Anmerkungen zur Objektorientierung (Wiederholung)
Die Mehrfachvererbung führt (wie schon beschrieben) zum sog. Diamond-Problem.
Mixins und Traits ermöglichen eine wiederverwendbare Menge von Attributen und
Methoden (ähnlich wie Klassen). Traits sind eine Variante der Mixins. Traits gibt es
inzwischen in vielen Programmiersprachen, zum Beispiel Scala.
Lothar Piepmeyer: Anders als in Java ist in Scala alles ein Objekt. Die Teilung in
primitive Typen und den Rest der Welt kennt Scala nicht. Unter der Haube bildet der
Compiler den Scala-Typen Int auf die Java-Typen int und Integer ab.
Rückblick und Ausblick
A-39
Die wichtigsten der bisherigen Aspekte
• Paradigma oder hybrid?
• Anweisungen, Sequenz, Auswahl, Wiederholung, Deklaration, break, continue
• Datentypsystem, Variable, Konstante, Operatoren, Ausdrücke, Speicherung
• Methoden und ihre Signatur
• Gültigkeit, Sichtbarkeit, Überladung
• Programmiertechniken, z. B. Rekursion
• Zuverlässigkeit von Programmen
• Ein- und Ausgabe, packages, ...
• Weitere Aspekte kommen im nächsten Semester!
Rückblick und Ausblick
A-40
Programmierausbildung
• Imperative, objektorientierte und Grundlagen der Programmierung:
◦ Programmieren I (Java)
◦ Programmieren II (Java, auch kleiner Blick auf andere Sprachen)
• Softwaretechnik:
◦ SoftwareEngineering I (UML)
◦ Softwareentwicklungspraktikum
(Java oder andere Sprache, UML)
• Funktionale Programmierung und Allgemeine Sicht auf Programmiersprachen:
◦ Programmieren für Fortgeschrittene
Rückblick und Ausblick
(Haskell)
A-41
Programmierausbildung
• Deduktive Programmierung und Weiteres zur Logik:
◦ Logik in der Informatik (Prolog)
• Bedeutung von Programmen:
◦ Semantik von Programmiersprachen
• Implementierung von Programmiersprachen:
◦ Compiler I, II
◦ Compilerbaupraktikum
• Entwicklung von Software für eine konkrete Anwendung:
◦ Softwaretechnisches Industriepraktikum
Rückblick und Ausblick
A-42
Programmieren I + II
Programmieren I: 6 LP, 2+2 (+ Rechnerübungen), im Wintersemester,
ab SS2016: auch im Sommersemester.
Inhalt: Grundzüge der imperativen, objektorientierten und funktionalen
Programmierung. Java.
Programmieren II: 6 LP, 2+2 (+ Rechnerübungen), im Sommersemester,
ab WS2016: auch im Wintersemester.
Inhalt: Vertiefung der objektorientierten Programmierung, auch kleiner Blick auf
andere Sprachen. Schwerpunkte: Programmierung von Datenstrukturen,
Parallelprogrammierung und Grafikprogrammierung.
Prüfungsvorleistung/Studienleistung (je nach Studiengang): Hausaufgaben
Prüfung: Klausur
Rückblick und Ausblick
A-43
Gehirn und Geist
In der Ausgabe Februar 2015 (Monatsheft) der Zeitschrift Gehirn und Geist erschien
ein Artikel mit dem Titel „Im Kopf des Programmierers“.
Zitat:
Während Laien im Quelltext von Computerprogrammen meist nur kryptische
Zeichen sehen, entschlüsseln Informatiker im Handumdrehen die Bedeutung des
Kodes. Forscher untersuchen, was dabei im Gehirn passiert.
von Janet Siegmund, Sven Apel und André Brechmann.
Rückblick und Ausblick
A-44
Herunterladen