| Imperative Programmierung | Deklarative Programmierung |
|---|---|
| Wie ist das Problem zu lösen? | Was ist das zu lösende Problem? |
| Variablen und Wertzuweisungen | Funktionen und formale, mathematische Logik |
| Anweisungsfolge | Audruck, der ein Ergebnis liefert |
| Imperative Programmierung | Deklarative Programmierung |
|---|---|
| Prozedurale Programmierung | Funktionale Programmierung |
| Objektorientierte Programmierung | Logische Programmierung |
| Prozedurale Programmierung | Objektorientierte Programmierung |
|---|---|
| Denken in Prozeduren | Daten im Mittelpunkt |
| Für jede Unterscheidung existiert eine eigene Methode | Objekt weiß selber, welche Antwort zu ermitteln ist |
0 und 1)| syntaktische Typkompatibilität | semantische Typkompatibilität |
|---|---|
| Welche Typbezeichner und Funktionssignaturen stehen zur Verfügung? | liefert eine Funktion das erwartete Ergebnis zurück? |
| Vorteile: - Unterstützt modulare Entwicklung | |
| - Nutzung neuer Datentypen, wie vordefinierte Datentypen | |
| Nachteil: Syntaktisch Korrekte Implementierung kann semantisch falsch sein |
Es gibt zwei unterschiedliche Typsysteme:
Typangabe ist bei der Dekleration erforderlich:
//Beispiel in Java
int i; // Java
//Beispiel in Pascal
var i: integer;
Typangabe kann aus der Verwendung abgeleitet werden (Typinferenz)
//Beispiel in Clojure
(def pi 3.14159)
| statische Typisierung | dynamische Typisierung |
|---|---|
| Typprüfung erfolgt zur Übersetzungszeit | Typprüfung folgt während der Ausführung des Programms |
Bsp: Java, C++, C# |
Bsp: Python, Perl, Php, Smalltalk |
| strenge Typsysteme | schwache Typsysteme |
|---|---|
| stellt Typensicherheit jederzeit sicher | lässt gelegentlich auch typfremde Operationen zu |
| explizite Typsysteme | implizite Typsysteme |
|---|---|
| verlangt für jede Variable die Angabe eines Typs | verlangt die Dekleration einer Variable und leitet den Typ der anderen aus der Verwendung ab |
| statisches Typsystem | dynamisches Typsystem Prolog |
|
|---|---|---|
| strenges Typsystem | implizites Typsystem Haskell, Standard ML |
implizites Typsystem Lisp, Clojure, Smalltalk |
explizites Typsystem Java |
explizites Typsystem | |
| schwaches Typsystem | implizites Typsystem | implizites Typsystem Javascript |
explizites Typsystem C |
explizites Typsystem |
(def filter
(fn [praed? lst]
(cond
(empty? lst) ()
(praed? (first lst))
(cons (first lst) (filter praed? (rest lst)))
:else (filter praed? (rest lst)))))
(* Filter *)
fun filter (praed, lst) =
if null lst
then []
else if praed (hd lst)
then
hd lst :: filter (praed, tl lst)
else filter (praed, tl lst)
(* Signatur von filter: fn : ('a -> bool) * 'a list -> 'a list *)
(* Lambda Ausdruck *)
fn x => x+1
(* Funktion benennen *)
val twice = (fn x => 2*x)
(* Funktionen mit Rekursion [fun statt fn] *)
fun fac n =
if (n=0)
then 1
else n*(fac (n-1))
(* Funktion mit getypten Parametern *)
fun pow (x:int, y:int) =
if y=0
then 1
else x * pow(x,y-1)
(* Tupel *)
val pair = (1,"abc")
(* Liste {1} *)
1::nil
(* Zugriff auf das erste Listenelement *)
hd list
(* Zugriff auf den Rest der Liste *)
tl list
(* Records [= HashMaps] *)
val car = {make = "Ford", built = 1904}
(* Zugriff auf HashMap-Einträge *)
#make car
(* Summieren von Listpaaren *)
fun sum_pair (a,b) = a + b;
fun sum_pair_list (lst) =
if (lst = nil)
then 0
else sum_pair (hd lst) + sum_pair_list (tl lst);
sum_pair_list [(2,3), (4,5)]; (* =14 *)
(* Extrahieren des ersten Elements von Listpaaren *)
fun get_first (a,b) = a;
fun firsts (lst) =
if lst = nil
then nil
else get_first (hd lst) :: (firsts (tl lst));
firsts [(2,3), (4,5)];
(* Datumsfunktionen (DD MM YYY) *)
fun ist_frueher (day1 : int*int*int, day2 : int*int*int) =
(#1 day1) < (#1 day2)
orelse (((#2 day1) < (#2 day2))
andalso ((#1 day1) = (#1 day2)))
orelse (((#3 day1) < (#3 day2))
andalso ((#2 day1) = (#2 day2))
andalso ((#1 day1) = (#1 day2)));
ist_frueher ((2,4,2017), (7,6,2017));
fun in_monat (datum:int*int*int, monat) = #2 datum = monat;
in_monat ((2, 6, 2017), 6);
fun kalenderdaten_in_monat (daten: (int*int*int) list, monat : int) =
if daten = nil
then nil
else in_monat(hd daten, monat) :: kalenderdaten_in_monat (tl daten, monat);
kalenderdaten_in_monat ([(2, 6, 2018), (5, 6, 2017)], 6);
fun contains (value: bool, lst: (bool) list) =
if lst = nil
then false
else
if (hd lst) = value
then true
else contains (value, tl lst);
fun daten_in_monat (daten: (int*int*int) list, monat: int) =
if daten = nil
then nil
else
if in_monat (hd daten, monat)
then (hd daten) :: daten_in_monat (tl daten, monat)
else daten_in_monat (tl daten, monat);
daten_in_monat ([(2, 6, 2018), (5, 9, 2017)], 6);
fun kalenderdaten_in_monaten (daten: (int*int*int) list, monate: (int) list) =
if monate = nil
then nil
else daten_in_monat(daten, hd monate) @ kalenderdaten_in_monaten(daten, tl monate);
kalenderdaten_in_monaten ([(2, 6, 2018), (5, 6, 2017), (9, 4, 2018), (9, 9, 2018)], [4, 6, 7]);
fun contains_date (date: int*int*int, lst: (int*int*int) list) =
if lst = nil
then false
else
if (hd lst) = date
then true
else contains_date (date, tl lst);
fun distinct (daten: (int*int*int) list) =
if daten = nil
then nil
else
if tl daten = nil
then (hd daten) :: nil
else
if contains_date (hd daten, tl daten)
then distinct (tl daten)
else (hd daten) :: distinct (tl daten);
fun kalenderdaten_in_monaten_2 (daten: (int*int*int) list, monate: (int) list) =
distinct (kalenderdaten_in_monaten (daten, monate));
distinct (kalenderdaten_in_monaten_2 ([(2, 6, 2018), (5, 6, 2017), (9, 4, 2018), (9, 9, 2018)], [4, 6, 4, 7]));
Erstellung neuer Datentypen in SML:
datatype shape =
Rectangle of real * real
| Circle of real
muster => ausdruck| getrenntfun shape_area s =
case s of
Rectangle(w, h) => w * h
| Circle(r) => 3.14159 * r * r
fun sum_list (xs : int list) =
if xs = nil
then 0
else hd(xs) + sum_list(tl xs)
fun sum_list xs =
case xs of
[] => 0
| x::xs’ => x + sum_list xs’
datatype exp = Constant of int
| Negate of exp
| Add of exp * exp
| Multiply of exp * exp;
fun eval exp =
case exp of
Constant(i) => i
| Negate(ex) => ~(eval(ex))
| Add(sum1, sum2) => eval(sum1) + eval(sum2)
| Multiply(fac1, fac2) => eval(fac1) * eval(fac2);
eval (Add (Constant 19, Negate (Constant 4)));
fun list_of_constants (lst: exp list) =
if lst = nil
then nil
else
case hd lst of
Constant(i) => i :: list_of_constants(tl lst)
| _ => list_of_constants(tl lst);
list_of_constants [(Add (Constant 19, Negate (Constant 4))), Constant 19, (Constant 5)];
fun get_bigger (a:int, b:int) =
if a > b
then a
else b;
fun largest_constant_helper(lst: int list) =
case lst of
[] => []
| c::[] => [c]
| c::c2::cs' => largest_constant_helper (get_bigger(c, c2) :: cs');
fun largest_constant(lst: exp list) = largest_constant_helper(list_of_constants(lst));
largest_constant [(Add (Constant 19, Negate (Constant 4))), Constant 19, (Constant 5)];
fun number_of_adds (lst: exp list) =
if lst = nil
then 0
else
case hd lst of
Add(a,b) => 1 + number_of_adds(tl lst)
| _ => 0 + number_of_adds(tl lst);
number_of_adds [(Add (Constant 19, Negate (Constant 4))), Constant 19, Constant 5, (Add (Constant 19, Negate (Constant 4)))];
(* Bisherige Form von mehreren Parametern *)
fun sorted3_tupled (x,y,z) = z >= y andalso y >= x
(* Curryfizierte Funktion *)
fun sorted3 x y z = z >= y andalso y >= x
(* Funktionen höherer Ordnung *)
val List.map = fn : (’a -> ’b) -> ’a list -> ’b list
val List.filter = fn : (’a -> bool) -> ’a list -> ’a list
val List.foldl = fn : (’a * ’b -> ’b) -> ’b -> ’a list -> ’b
// list
'(1 2 3)
// vector
[1 2 3]
// set
#{1 2 3}
// map
{:a 1, :b 2}
// Function
(defn greet [name] (str "Hello, " name) )
// Bedingungen
(if (even? 2)
"even"
"odd")
(cond
(< x 2) "Case 1"
(< x 10) "Case 2"
:else "Case 3")
// Zugriff auf eine Liste
(first (cons a list)) = a
(rest (cons a list)) = list
(def make-add
(fn [a]
(fn [b]
(+ a b))))
(def make-prepend
(fn [a]
(fn [b]
(cons a b))))
eval und applyeval wertet den Ausdruck aus und gibt das Ergebnis zurückapply erwartet eine Funktion und eine Sequenz von Argumenten und wendet die Funktion auf die Elemente der Sequenz an| Funktionale Programmierung | Objektorientierte Programmierung |
|---|---|
| Fehlen von Mutation | Gebrauch von Mutation |
| Fehlen von Zuweisungen | Gebrauch von Zuweisungen |
| Funktionen | Objekte (Funktionen mit internen Daten) |
| Funktionen | Methoden |
Gilt nur für Java 8 oder größer!
map, filter und reduceConsumer<T> - Operation ohne RückgabeSupplier<T> - Fabrik, die ein neues oder existierendes Objekt liefertPredicate<T> - Prüfung einer Bedingung für ein ArgumentFunction<T> - Operation mit Resultatpublic static void main(final String[] args) {
FluentMailer.send(mailer ->
mailer.from("build@agiledeveloper.com")
.to("venkats@agiledeveloper.com")
.subject("build notification")
.body("...much better..."));
}
Häufig als “Erweiterung” der relationalen Programmierung betrachtet
natural(z).
natural(s(N)):- natural(N).
% Beispiel "plus"
plus(z, N, N):- natural(N).
% Definition von Variablen durch Großbuchstaben
plus(s(N), M, s(X)):- plus(N, M, X).
% Definition von beliebigen Variablen durch "_"
print(_).
vater(hans, paul).
vater(hans, anna).
% Abfrage
?- vater(X,Y).
X=hans;
Y=paul; % weitere Abfrage durch Simikolon
X=hans;
Y=anna. % bei weiterer Abfrage würde "false." kommen
% Regel
% Hinweis: "," stehen für UND-Verknüpfungen
father(Dad, Child) :- parent(Dad, Child), male(Dad).
% Listenoperationen
member(X, [X, Y, Z]).
append([A], [X, Y, Z]).
mapList(praed(3), [1, 2, 3], X).
count([],0).
% "|" entspricht cons
% "is" entspricht Zuweisung
count([_|Tail],N) :- count(Tail, X), N is X+1.
% Abfragen
?- count([a, b, c], N).
N = 3.
?- count([a, b, c], 3).
true.
cut und failcutDarstellung durch , !.
failDarstellung durch , fail.
Negation mit cut und failDarstellung durch , !, fail.
mag(karl, X) :- salami_pizza(X),!,fail.
mag(karl, X) :- pizza(X).
pizza(X) :- vier_jahreszeiten_pizza(X).
pizza(X) :- salami_pizza(X).
pizza(X) :- champignon_pizza(X).
vier_jahreszeiten_pizza(vklein).
vier_jahreszeiten_pizza(vgross).
salami_pizza(s).
champignon_pizza(c).
?- mag(karl,c).
true.
?- mag(karl,s).
false.
mag(karl, X) liefert falsecut and fail:Negation
neg(Ziel) :- Ziel,!,fail.
neg(Ziel).
mag(karl, X) :- pizza(X), neg(salami_pizza(X)).
Celsius zu Fahrenheit Converter
(def celsius-fahrenheit-converter
(fn [c f]
(let [u (make-connector)
v (make-connector)
w (make-connector)
x (make-connector)
y (make-connector)]
(multiplier c w u)
(multiplier v x u)
(adder v y f)
(constant 9 w)
(constant 5 x)
(constant 32 y)
'ok)))
cf(C, F) :- {9*C=5*(F-32)}.
Typisches Vorgehen
Typische Anwendungsgebiete
| Nebenläufigkeit | Parallelität |
|---|---|
| mehrere unabhängige Aufgaben zur gleichen Zeit | Aufteilung einer Aufgabe in Teilaufgaben |
| Aufgaben konkurrieren um Ressourcen | |
| Resultate einzelner Aufgaben beeinflussen evtl. das Verhalten anderer Aufgaben | Resultate einzelner Aufgaben beeinflussen nicht das Verhalten anderer Aufgaben |
| Nicht-Determinismus | Determinismus bleibt erhalten |
| Können Deadlocks verursachen | |
| Können Raceconditions verursachen | |
| Fehlverhalten schwer zu reproduzieren |
| Prozess | Thread |
|---|---|
| Programm in der Ausführung | Ausführungsstrang eines Prozesses |
| benötigt Ressourcen (Speicher, Prozessor, Dateien etc.) | benötigt Prozessor und eigenen Stack |
| verwendet Programmcode, Dateien etc. | |
| mehrere Threads in einem Prozess möglich |
synchronized]class Test {
static int n;
static Object lock = new Object();
void incrementN() {
synchronized(lock) {
n = n + 1;
}
}
}
In Java gibt es Threadsichere Datentypen. Bsp:
java.util.concurrent.atomic
java.util.concurrent.ConcurrentHashMapjava.util.concurrent.CopyOnWriteArrayListjava.util.concurrent.BlockingQueuemap als ideales Beispiel zur ParallelisierungParallelsort