Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

85
© Zühlke 2011 Januar 2011 Dr. Klaus Alfert Dr. Bernd Löchner Folie 1 Jenseits von Fakultät und Fibonacci: Architektur Funktionaler Programme Dr. Klaus Alfert Dr. Bernd Löchner

description

Funktionale Programmierung bietet viele Möglichkeiten, die Herausforderungen moderner Multi-Core-Rechner einfacher als mit klassischer OO-Programmierung zu bewältigen. Dadurch verlieren Objekte ihre dominante Rolle und damit die klassische Design- und Architekturmuster einen Teil ihrer Basis. Wir zeigen, welche Muster nicht mehr benötigt werden, welche in abgewandelter Form weiterhin bestehen und welche neuen Muster und Konstruktionsprinzipien wichtig und hilfreich sind. Die Grundideen können auch in der OO-Welt profitabel eingesetzt werden.

Transcript of Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Page 1: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Januar 2011

Dr. Klaus Alfert Dr. Bernd Löchner

Folie 1

Jenseits von Fakultät und Fibonacci: Architektur Funktionaler Programme

Dr. Klaus Alfert Dr. Bernd Löchner

Page 2: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner
Page 3: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Januar 2011

Dr. Klaus Alfert Dr. Bernd Löchner

Folie 3

Warum ist Funktionale Programmierung in vieler Munde?

Page 4: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Sun T 2 »Niagara 2« 2007, 8 Cores × 8 Threads

Page 5: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Intel i7 »Nehalem« 2008, 4 Cores × 2 Threads

Page 6: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

IBM POWER 7, 2010, 8 Cores × 4 Threads

Page 7: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Oracle T 3 »Rainbow Falls« 2010, 16 Cores × 8 Threads

Page 8: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Intel Cloud Computing on a Chip 2009, 48 Cores (Prototyp)

Page 9: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Januar 2011

Dr. Klaus Alfert Dr. Bernd Löchner

Folie 9

Warum ist Nebenläufigkeit mit Objekten schwierig?

Page 10: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Objekte haben eine Identität

:2 :3

:1

Page 11: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Objekte haben einen (lokalen) Zustand

:2 :3

:1

Page 12: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Objekte haben Verhalten

:2 :3

:1

Page 13: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Multithreading erfordert Locks

:2 :3

:1

Page 14: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Ein hoher Grad an Nebenläufigkeit wird leicht unübersichtlich

:2 :3

:1

Page 15: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Ein hoher Grad an Nebenläufigkeit wird leicht unübersichtlich

:2 :3

:1

Page 16: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Wie kann funktionale Programmierung hier helfen?

Page 17: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Januar 2011

Dr. Klaus Alfert Dr. Bernd Löchner

Folie 17

Was unterscheidet FP von OOP?

Page 18: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Zu den Programmbeispielen

Beispiele in Haskell & Erlang

• Haskell ist puristisch elegant

• Erlang hat Industrial-Strength

Die Beispiele sind aber alle übertragbar in andere funktionale Programmiersprachen. F#

Page 19: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

A LISP programmer knows the value of everything, but

the cost of nothing.

–Alan J. Perlis Epigrams of Programming

Page 20: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Werte, Variablen, Veränderliche

Was sind imperative Variablen?

• Namen für Adressen von Speicherzellen

• Abstraktionsniveau: Assembler

• Objekte haben eine Identität: Entspricht einer Adresse von Speicherzellen

Was sind funktionale Variablen?

• Namen für Werte: „Sei x beliebig, aber fest“

• Variablen werden an Werte „gebunden“

• Abstraktionsniveau: Mathematik

• Notwendig: Effiziente Abbildung auf Speicherzellen durch Laufzeitsystem

42

42

x

x

Page 21: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Objekte versus Werte

:1 42 :1 42 :1 42

Funktionen erzeugen aus alten Werte neue!

:2 42 42 42

Copy Gleich, aber nicht identisch

Gleich und identisch

Page 22: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Page 23: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Rekursion statt Iteration: Hyper-Fakultät (Sloane: A Handbook of Integer Sequences)

Fakultät ist für Kinder – Hyper-Fakultät ist für Erwachsene

H(n) = 1, 1, 4, 108, 27648, 86400000, 4031078400000, 3319766398771200000, 55696437941726556979200000, 21577941222941856209168026828800000, 215779412229418562091680268288000000000000000, 61564384586635053951550731889313964883968000000000000000, …

n

k

kknH1

)(

Page 24: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Rekursion statt Iteration: Hyper-Fakultät (Sloane: A Handbook of Integer Sequences)

Imperativ: Zuweisungsorientiert

hfac(n): r := 1; while n > 0 do r := r * n^n; n := n – 1; od return r;

Rekursiv: Werteorientiert

hfac(n)-> if n == 0 then 1 else n^n * hfac(n-1)

Page 25: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Rekursion statt Iteration: Hyper-Fakultät (Sloane: A Handbook of Integer Sequences)

Imperativ: Zuweisungsorientiert

hfac(n): r := 1; while n > 0 do r := r * n^n; n := n – 1; od return r;

Berechnung: hfac(3)

3 n

? r 1 27

2

108

1

108

0

Page 26: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Rekursion statt Iteration: Hyper-Fakultät (Sloane: A Handbook of Integer Sequences)

Imperativ: Zuweisungsorientiert

hfac(n): r := 1; while n > 0 do r := r * n^n; n := n – 1; od return r;

Rekursiv: Werteorientiert

hfac(n)-> if n == 0 then 1 else n^n * hfac(n-1)

Page 27: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Rekursion statt Iteration: Hyper-Fakultät (Sloane: A Handbook of Integer Sequences)

Berechnung:

Rekursiv: Werteorientiert

hfac(n)-> if n == 0 then 1 else n^n * hfac(n-1)

if n == 0 then 1 else n^n * hfac(n-1)

3 n fun

hfac(3)

if n == 0 then 1 else n^n * hfac(n-1)

2 n fun

if n == 0 then 1 else n^n * hfac(n-1)

1 n fun

hfac(2)

hfac(1)

hfac(0)

if n == 0 then 1 else n^n * hfac(n-1)

0 n fun

1 1

1

4

108

Page 28: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Komplexe Werte sind oft baumartig

D11

D112 D111

C D A B

C1 C2

C21 C22 D12

D122 D121

D1

{ vorname : „Martin“, nachname : „Mustermann“, anschrift : { strasse : „Hauptstrasse 23“, ort : { plz : „76541“, stadt : „Neustadt“ } }, kurse : [ { id : „Mo1“, title: „Tutorial C#“ }, { id : „Ndo4“, title: „Architektur“ } ] }

Page 29: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Wie ändert man komplexe Werte?

5

8 3

15

20

21 18

26

27 25

28

35

41 33

24

update (Tree, Value) Tree

Page 30: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Update: Ersetze 41 durch 42

5

8 3

15

20

21 18

26

27 25

28

35

41 33

24

28

24

35

42

Alter Baum Neuer Baum

Beide Bäume existieren gleichzeitig!

Page 31: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Pattern Matching

sum ([]) -> 0; sum ([X | Xs]) -> X + sum (Xs).

abs (N) when N >= 0 -> N; abs (N) -> -N.

length [] = 0 length (x:xs) = 1 + length xs

zip [] _ = [] zip _ [] = [] zip (x:xs) (y:ys) = (x,y) : zip xs ys

Page 32: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Higher-order Funktionen, Polymorphie und Lambda-Ausdrücke

map :: (a -> b) -> [a] -> [b]

map f [] = []

map f (x:xs) = f x : map f xs

map abs [-2 .. 2]

>> [2, 1, 0, 1, 2]

map (\x -> x*x) [-2 .. 2]

>> [4, 1, 0, 1, 4]

Page 33: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Algebraische Datenstrukturen

data Tree a = Empty

| Node (Tree a) a (Tree a)

mapTree :: (a -> b) -> Tree a -> Tree b

mapTree f Empty = Empty

mapTree f (Node l x r) =

Node (mapTree f l) (f x) (mapTree f r)

data Color = Green | Red | ...

autumn t = mapTree change t

where change Green = Red

change c = c

Page 34: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Erlang hat Closures – und Clojure auch (und Scala, F#, …)

mk_mul_abs (M) -> fun (N) when N > 0 -> M * N; (N) -> M * (-N) end.

Ma3 = mk_mul_abs (3). lists:map(Ma3, [-2, -1, 0, 1, 2]).

>> [6, 3, 0, 3, 6]

when N > 0 -> M * N; M * (-N)

3

N fun

mk_mul_abs M

Ma3

Page 35: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Haskell erlaubt Partial Application

parabola a b c x = a*x^2 + b*x + c

p1 :: Double -> Double

p1 = parabola 4.2 -2.0 3.5

y = p1 1.0

linear = parabola 0.0

l1 = linear 3.0 2.1

a*x^2 + b*x + c

3.5 x fun

fun c

p1 fun b

a fun

-2.0

4.2

a*x^2 + b*x + c

x c b a fun

Page 36: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Programmierung im Großen

Verantwortlichkeiten bündeln

• Module, APIs und Interfaces

• Kontrakte: Daten, Funktionen, Eigenschaften

Information Hiding

• Sichtbarkeiten, Namespaces

• Implementierungsinterna verbergen

Wie in OOP:

Benötigt Augenmaß und Disziplin

Beispiel: Pattern Matching

Werteorientierung und Higher-order Funktionen

ermöglichen andere Schnittstellen und Kontrakte

Page 37: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Funktionale Programmierung = Werteorientierung & Higher-order Funktionen

Page 38: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Welche Auswirkungen hat Funktionale Programmierung auf Architektur und Design?

Page 39: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Eoin Wood: Software architecture is the set of design decisions which, if made incorrectly, may cause your project to be canceled.

Page 40: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Grady Booch: Architecture represents the significant design decisions that shape a system, where significant is measured by cost of change.

Page 41: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

ANSI/IEEE 1471-2000 The fundamental organization of a system, embodied in its components, their relationships to each other and the environment, and the principles governing its design and evolution.

Page 42: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

ANSI/IEEE 1471-2000 The fundamental organization of a system, embodied in its components, their relationships to each other and the environment, and the principles governing its design and evolution.

Page 43: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

High-Level Architektur

Page 44: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Architektur auf Marketing-Niveau: Ein typisches „Marchitecture“-Diagramm

DB

System im Fokus

DWH

CRM Server

Auftrags-verwaltung

Kunden-verwaltung

Pricing Logistik

Page 45: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Enterprise Architektur: Funktionalität bleibt lokal, Kommunikation über Werte

DB

System im Fokus

DWH

CRM Server

Auftrags-verwaltung Kunden-

verwaltung

Pricing Logistik HTML

JSON/REST

QuerySet

AMQP

SOAP

Service Bus

Portal Server

MQ SOAP

Host

SOAP

Page 46: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

High Level Architektur: Grobzerlegung bleibt bestehen

Treiber:

• Primär fachliche Zerlegung in Aufgaben- und Verantwortlichkeitsgebiete

• Reflektiert auch die Organisation (Conway’s Law)

Konsequenzen

• Architektur auf dieser Ebene ist unabhängig von der Implementierungstechnologie

• Interna der Komponenten/Subsysteme sind irrelevant

• Kommunikation erfolgt über Werte, Funktionen bleiben lokal und werden nicht transportiert

Page 47: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Mittlere Architektur

Page 48: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Mittlere Architektur: Geprägt von nicht-funktionalen Systemanforderungen

Portabilität Wartbarkeit

Funktionalität

Zuverlässig- keit

Bedienbarkeit

Effizienz Dokumentation

Machbarkeit

Gliederung gemäß ISO/IEC 9126

Page 49: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Enterprise Java

Page 50: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Ein Blick auf Enterprise Java

Historisch:

• Transaktionsmonitor für verteilte Objekte

• Anbindung an (Legacy)-Datenbanken

Ausgelegt für

• Informationssysteme

• Hohen Durchsatz

• Skalierbarkeit

PortabilitätWartbarkeit

Funktionalität

Zuverläs-sigkeit

Bedienbarkeit

EffizienzDoku-

mentationMachbarkeit

Page 51: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Struktur: N-Tier-Schichtenarchitektur

http://download.oracle.com/javaee/6/tutorial/doc/bnaay.html

Page 52: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Einfluss von Java

Everything is an Object

• Auch für Dinge, die eigentlich keine Objekte sind (Stateless Session Beans, MDB, Backing Beans, Servlets, Transaktionen)

Transparente Remote-Aufrufe (RMI)

Thread-Management nur im Container

• Das Lock-Model von Java erlaubt keine Komposition von Concurrent Libraries

Interfaces anstatt abstrakter Klassen

Page 53: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Erlang/OTP

To Iterate is Human, to Recurse Divine – L. Peter Deutsch

Page 54: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Ein Blick auf Erlang/OTP

Historisch:

• Soft-Realtime Systeme, PBX, Telco

Ausgelegt für

• (sehr hohe) Zuverlässigkeit und Fehlertoleranz

• Skalierbarkeit mit massiver Parallelität

• Kommunikationssysteme

Anwendungsbeispiele

• Diverse Telco-Systeme von Ericsson

• Ejabberd, RabbitMQ, CouchDB PortabilitätWartbarkeit

Funktionalität

Zuverläs-sigkeit

Bedienbarkeit

EffizienzDoku-

mentationMachbarkeit

Page 55: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

OTP besteht aus lose gekoppelten „Anwendungen“ …

Anwendung Web Server

odbc

crypto

gen_tcp

uses

Page 56: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

… und aus Supervisor-Prozesshierarchien

Anwendung

Supervisor

Worker Supervisor

Worker Worker überwacht

Page 57: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Einfluss von Erlang auf OTP

Erlang stellt die Basismechanismen bereit

• Pure Funktionen, Datenstrukturen sind immer Werte

• Nebenläufigkeit durch Prozesse – Prozesse sind referenzierbar Entitäten im Sinne von Domain Driven Design

– Halten lokalen State, teilen sich aber keinen State!

• Massive Parallelität durch leichtgewichtige Prozesse und asynchrones Messaging

• Monitoring von Prozessen über VM-Grenzen hinaus

• Hot-Code Swapping: Updates im laufenden System

Nachbau in Scala: Akka (www.akka.io)

Page 58: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Mittlere Architektur: Domäne der Blue-Print-Architekturen

Standardarchitektur für eine bestimmte Systemklasse

• Anwendungsdomäne und -typ sind relevant

• Abgestimmt auf Hardware und Infrastruktur

Geprägt von den nicht-funktionalen Anforderungen

• Priorisierung und Balancierung der Qualitätsattribute

Das technisch Machbare bestimmt den Lösungsraum

• Programmiersprachen

• Laufzeitsysteme

• Bibliotheken PortabilitätWartbarkeit

Funktionalität

Zuverlässig-keit

Bedienbarkeit

EffizienzDokumentation

Machbarkeit

PortabilitätWartbarkeit

Funktionalität

Zuverlässig-keit

Bedienbarkeit

EffizienzDokumentation

Machbarkeit

Page 59: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Kleinteilige Architektur

Page 60: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Page 61: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Peter Norvig: Design Patterns in Dynamic Languages (1998) Analyse der Design Patterns aus Lisp/Dylan-Sicht

• GoF verwendet C++ und Smalltalk

Unterscheidung von Implementierungsebenen

• Unsichtbar: Wird von der Sprache abgedeckt

• Informell: Wird jedes mal neu implementiert

• Formell: Implementierung mit Template oder Macro

Norvigs Fazit für die 23 GoF Patterns:

• 16 werden deutlich einfacher oder unsichtbar

Page 62: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

GoF Command Pattern

http

://e

n.w

ikip

edia

.org

/wik

i/Co

mm

and_

patte

rn

Page 63: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Ein Command ist eine Closure

shutdown_command(Receiver) -> fun() -> Receiver ! {shutdown, now} end.

@Client: MyMachine = …, Cmd = shutdown_command(MyMachine),

add_action(Cmd, Target),

@Target: ... Cmd().

Receiver ! {shutdown, now}

MyMachine

() fun

fun Receiver

Cmd

Page 64: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Commands mit Undo sind Closures mit Pattern Matching

start_command(Receiver) -> fun(do) -> Receiver ! {start, now}; (undo) -> Receiver ! {shutdown, now} end.

@Client MyMachine = …, Cmd = start_command(MyMachine),

@Target ... Cmd(do), ... Cmd(undo).

Receiver ! {start, now}

MyMachine

(do) fun

fun Receiver

Cmd

Receiver ! {shutdown, now}

(undo)

Page 65: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

GoF Visitor Pattern

Ein Composite

http

://e

n.w

ikip

edia

.org

/wik

i/Vi

sito

r_pa

ttern

“Languages that support double- or multiple dispatch lessen the need for the Visitor pattern.

(CLOS actually supports multiple dispatch).” [GoF: p.339]

Page 66: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Composite = Algebraischer Datentyp Visitor = Durchlauf der Struktur

data CarElement = Car [CarElement] | Wheel String | Body | Engine

toString Body = ["Visit Body"] toString Engine = ["Visit Engine"] toString (Wheel s) = ["Visit Wheel " ++ s] toString (Car es) = concat (map toString es) ++ ["Visit Car"]

doCar Body = ["Moving my Body"] doCar Engine = ["Starting my Engine"] doCar (Wheel s) = ["Kicking Wheel " ++ s] doCar (Car es) = concat (map doCar es) ++ ["Starting my Car"]

Die Java Implementierung bei Wikipedia braucht dafür ca. 100 Zeilen

Page 67: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Charakteristik der GoF Patterns (1)

Creational Patterns

• Factories und Builder lösen allgemeine Probleme, unabhängig von OO, auch in C, Modula2, Haskell, Erlang

• Prototypen und Singletons verschwinden

Structural Patterns

• Interface-Probleme und -Lösungen sind sprachunabhängig (Facade, Bridge, Adapter, Proxy)

• Composite und Decorator werden unsichtbar

Page 68: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Charakteristik der GoF Patterns (2)

Behavioral Patterns

• Können durch Lambdas, Pattern Matching, … anders realisiert werden.

• Einige werden unsichtbar, andere sind nicht immer offensichtlich umzusetzen.

Generelle Beobachtung:

• Patterns, die auf Objektidentitäten basieren, müssen ganz anders umgesetzt werden.

Page 69: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Januar 2011

Dr. Klaus Alfert Dr. Bernd Löchner

Folie 69

Funktionale Patterns

http://www.flickr.com/photos/robbie73/

Page 70: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Standardisierte Rekursion

Listenfunktionen in Haskell:

sum [] = 0 sum (x:xs) = x + sum xs

product [] = 1 product (x:xs) = x * product xs

allTrue [] = True allTrue (x:xs) = x && allTrue xs

Extrahiere das Rekursionsschema

foldList startVal combFct [] = startVal foldList startVal combFct (x:xs) = combFct x (foldList startVal combFct xs)

sum = foldList 0 (+)

product = foldList 1 (*)

allTrue = foldList True (&&)

Page 71: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Standardisierte Rekursion

Mit foldList können viele Listenfunktionen implementiert werden

length [] = 0 length (x:xs) = 1 + length xs

map f [] = [] map f (x:xs) = f x : map f xs

length = foldList 0 cFct where cFct x len = 1 + len

map f = foldList [] cFct where cFct x ys = f x : ys

Page 72: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Standardisierte Rekursion für Algebraische Datentypen

Generalisiere für andere Datenstrukturen data Tree a = Empty

| Node (Tree a) a (Tree a)

foldTree eVal cFct Empty = eVal

foldTree eVal cFct (Node l x r) =

cFct (foldTree eVal cFct l) x (foldTree eVal cFct r)

sumTree = foldTree 0 cFct where cFct sl x sr = sl + x + sr

mapTree f = foldTree Empty cFct where cFct ml x mr = Node ml (f x) mr

heightTree = foldTree 0 cFct where cFct hl x hr = 1 + max hl hr

Page 73: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Auch im Visitor findet sich strukturierte Rekursion

data CarElement = Car [CarElement] | Wheel String | Body | Engine

visit :: (CarElement -> a) -> CarElement -> [a] visit f (Car es) = concat (map (visit f) es) ++ [f (Car es)] visit f x = [f x]

printCar car = visit toString car where toString Body = "Visit Body" toString Engine = "Visit Engine" toString Wheel s = "Visit Wheel " ++ s toString Car es = "Visit Car"

Separation of Concerns

Page 74: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Recursion is the goto of functional programming.

–Erik Meijer

Page 75: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Leichtgewichtige Threads

Erlang Prozesse sind nebenläufige, meist rekursive Funktionen

CalcProc = spawn(fun() -> calc_loop(0))

calc_loop(Acc) -> NewAcc = receive {mul, X} -> Acc * X; {add, X} -> Acc + X; clear -> 0; {get, Pid} -> Pid ! {result, Acc}, Acc; _IgnoredMsg -> Acc end, calc_loop(NewAcc).

Auswahl der Nachrichten durch Pattern Matching

Funktioniert dank Tail Call Optimization

Page 76: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Nebenläufige Endliche Automaten durch Prozesse, Funktionen und Messaging statt State-Pattern

Idle

Ringing Dial

Connected off_hook

on_hook

incoming off_hook

idle() -> receive {Number, incoming} -> start_ringing(), ringing(Number); off_hook -> start_tone(), dial() end. ringing(Number) -> receive {Number, off_hook} -> stop_ringing(), connected(Number); {Number, other_on_hook} -> stop_ringing(), idle() end.

other_ on_hook

Cesarini/Thompson: Erlang Programming 2009

Page 77: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Lazy Evaluation und unendliche Datenstrukturen

Lazy Evaluation:

(Teil-)Ausdrücke werden nur ausgewertet, wenn sie benötigt werden

head (x:xs) = x

Mit Lazy Evaluation gilt:

head [42.0, 1.0/0] == 42.0

Essentiell, um eigene Kontrollstrukturen zu definieren

unless cond x y = if !cond then x else y

Ideal für DSLs

Page 78: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Lazy Evaluation und unendliche Datenstrukturen

Mit Lazy Evaluation werden (potentiell) unendliche Datenstrukturen möglich

nats = [0 ..] take 5 nats == [0, 1, 2, 3, 4]

Wurzel-Berechnung nach Newton-Raphson:

sqrtSequence n = iterate (next n) n where next n x = (x + n/x)/2.0

sqrtSequence 2

>> [2.0, 1.5, 1.4166666666666665, 1.4142156862745097, 1.4142135623746899, 1.414213562373095, 1.414213562373095, 1.414213562373095, 1.414213562373095, …

iterate f n = [n,f(n),f2(n),f3(n), …]

http

://w

ww

.flic

kr.c

om/p

hoto

s/ro

bbie

73/

Page 79: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Pipes and Filters

Die Mächtigkeit der Unix-Shell kommt durch Pipes&Filters Konstruktionen cat *.txt | tr –sc A-Za-z '\n' | tr a-z A-Z | sort | uniq –c | sort –nr | head

Allgemein

prg1 –p1 <arg | prg2 –p2 | prg3 –p3 | prg4 –p4

Dies geht auch mit lazy Lists und Funktionskomposition

fct4 p4 . fct3 p3 . fct2 p2 . fct1 p1 $ arg

Idiomatisch in Haskell

Partial Application

Listen als Transfer-Container

Funktions- komposition

enspricht Pipe

Funktions- applikation enspricht <

Page 80: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Map/Reduce

Berechnung der (unabhängigen)

Zwischenergebnisse

Zusammenfassung

zum Endergebnis

Inspiration für s Map-Reduce-Framework (C++)

x1

x2

.

.

.

xn

f(x1)

f(x2)

.

.

.

f(xn)

map f reduce y = f(x1) … f(xn)

Page 81: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Was es sonst noch gibt

Eine Reihe weiterer Themen müssen wir auslassen

• Memoization

• Kombinatoren

• Monaden

• Macros

• Typeful Programming

• Continuations

• Co-Algebraische Konstruktionen

• …

Page 82: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

Fazit

Page 83: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Funktionale Programmierung

Andersartiger Programmierstil

• Neue Abstraktionen und Kombinationsmöglichkeiten

• Andere Zerlegung von Problemen

• Andere Denkweisen und Idiome

Einfachere Strukturen machen das Leben leichter

• Keine (kaum) Seiteneffekte

• Pure Functions

• Testen und Parallelität werden sehr viel einfacher

Page 84: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner

© Zühlke 2011

Auswirkungen auf Architektur

Vieles bleibt gleich

• Architekturtreiber sind weiterhin die Qualitätsattribute

• Patterns werden zur Kommunikation für die Entwickler benötigt

Kreativität und Augenmaß bleiben zwei wichtige Eigenschaften der Architekten

• Gutes Design

• Klare Verantwortlichkeiten

Page 85: Oop2011 jenseits von fakultät und_fibunacci_alfert_loechner