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 apply
eval
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 anFunktionale 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 reduce
Consumer<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 fail
cut
Darstellung durch , !.
fail
Darstellung durch , fail.
Negation mit cut und fail
Darstellung 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.ConcurrentHashMap
java.util.concurrent.CopyOnWriteArrayList
java.util.concurrent.BlockingQueue
map
als ideales Beispiel zur ParallelisierungParallelsort