Reaktive Programmierung
Vorlesung 1 vom 05.04.17: Was ist Reaktive Programmierung?
Christoph Lüth, Martin Ring Universität Bremen Sommersemester 2017
22:56:54 2017-06-06 1 [36]
Organisatorisches
I Vorlesung: Mittwochs 14-16, MZH 1110
I Übung: Donnerstags 12-14, MZH 1450 (nach Bedarf)
I Webseite:www.informatik.uni-bremen.de/~cxl/lehre/rp.ss17 I Scheinkriterien:
IVoraussichtlich 6 Übungsblätter
IAlle bearbeitet, insgesamt 40% (Notenspiegel PI3)
IÜbungsgruppen 2 – 4 Mitglieder
IDanach: FachgesprächoderModulprüfung
RP SS 2017 2 [36]
Warum Reaktive Programmierung?
Herkömmliche Sprachen:
IPHP, JavaScript, Ruby, Python IC, C++, Java
I(Haskell) Eigenschaften:
IImperativundprozedural ISequentiell
Zugrundeliegendes Paradigma:
. . . aber die Welt ändert sich:
I DasNetzverbindet Rechner I Selbst eingebettete Systeme sind
vernetzt (Auto: ca. 130 Proz.) I Mikroprozessoren sindmehrkernig I Systeme sindeingebettet,
nebenläufig,reagierenauf ihre Umwelt.
RP SS 2017 3 [36]
Probleme mit dem herkömmlichen Ansatz
Programm
Daten Eingabe
Ausgabe
Daten Programm
Eingabe Ausgabe
Daten Programm
Eingabe Ausgabe
Eingabe
AusgabeProgramm Daten
Eingabe Ausgabe
Eingabe Ausgabe
Eingabe
Ausgabe
Daten Programm
Eingabe Ausgabe
Eingabe Ausgabe
Eingabe
Ausgabe Eingabe Ausgabe
Daten Programm
Eingabe Ausgabe
Eingabe Ausgabe
Eingabe Ausgabe Eingabe
Ausgabe Eingabe Ausgabe
IProblem:Nebenläufigkeit
INebenläufigkeit verursacht Synchronisationsprobleme
IBehandlung:
I Callbacks (JavaScript, PHP)
I Events (Java)
I Global Locks (Python, Ruby)
I Programmiersprachenkonstrukte:
Locks, Semaphoren, Monitore
RP SS 2017 4 [36]
Amdahl’s Law
“The speedup of a program using multiple processors in parallel computing is limited by the sequential fraction of the program. For example, if 95% of the program can be parallelized, the theoretical maximum speedup using parallel computing would be 20×as shown in the diagram, no matter how many processors are used.”
20.00 18.00 16.00 14.00 12.00 10.00 8.00 6.00 4.00 2.00 0.00
Speedup 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536
NumberLofLProcessors Amdahl’sLLaw
ParallelLPortion 50%
75%
90%
95%
Quelle: Wikipedia
RP SS 2017 5 [36]
The Reactive Manifesto
I http://www.reactivemanifesto.org/
Responsive
Resilient
Message Driven Elastic
RP SS 2017 6 [36]
Was ist Reaktive Programmierung?
I ImperativeProgrammierung: Zustandsübergang I ProzeduralundOO: Verkapselter Zustand
I FunktionaleProgrammierung: Abbildung (mathematische Funktion) I ReaktiveProgrammierung:
1.Datenabhängigkeit
2.Reaktiv=funktional+nebenläufig
Datenflusssprachen (data flow languages)
I Frühe Sprachen: VAL, SISAL, ID, LUCID (1980/1990) I Heutige Sprachen: Esterel, Lustre (Gérard Berry, Verimag)
IKeineZuweisungen, sondernDatenfluss
ISynchron:alle Aktionen ohne Zeitverzug
IVerwendung in der Luftfahrtindustrie (Airbus)
Struktur der VL
I Kernkonzeptein Scala und Haskell:
I Nebenläufigkeit: Futures, Aktoren, Reaktive Ströme
I FFP: Bidirektionale und Meta-Programmierung, FRP
I Robustheit: Eventual Consistency, Entwurfsmuster
I BilingualerÜbungsbetriebundVorlesung
I KeinScala-Programmierkurs
I Erlernen von Scala ist nützlicherSeiteneffekt
RP SS 2017 9 [36]
Fahrplan
I Einführung
I Monaden als Berechnungsmuster I Nebenläufigkeit: Futures and Promises I Aktoren I: Grundlagen
I Aktoren II: Implementation I Bidirektionale Programmierung I Meta-Programmierung I Reaktive Ströme I I Reaktive Ströme II
I Functional Reactive Programming I Software Transactional Memory I Eventual Consistency I Robustheit und Entwurfsmuster I Theorie der Nebenläufigkeit, Abschluss
RP SS 2017 10 [36]
Rückblick Haskell
RP SS 2017 11 [36]
Rückblick Haskell
I Definition von Funktionen:
Ilokale Definitionen mitletundwhere
IFallunterscheidung und guarded equations
IAbseitsregel
IFunktionen höherer Ordnung
I Typen:
IBasisdatentypen:Int,Integer,Rational,Double,Char,Bool
IStrukturierte Datentypen:[α],(α,β)
IAlgebraische Datentypen:dataMaybeα= Justα | Nothing
RP SS 2017 12 [36]
Rückblick Haskell
I Nichtstriktheit und verzögerte Auswertung
I Strukturierung:
I Abstrakte Datentypen
I Module
I Typklassen
RP SS 2017 13 [36]
Ein- und Ausgabe in Haskell
Umwelt Haskell
Aktionen
Umwelt Reine
Funktionen
Haskell
Problem:
IFunktionen mit Seiteneffekten nicht referentiell transparent.
I readString :: . . .→String??
Lösung:
ISeiteneffekte am Typ erkennbar IAktionenkönnennurmit
Aktionenkomponiert werden I„einmal Aktion, immer Aktion“
RP SS 2017 14 [36]
Aktionen als abstrakter Datentyp
I ADT mit OperationenKompositionundLifting
I Signatur:
typeIOα
(=) :: IOα→ (α→IOβ) →IOβ return :: α→ IOα
I PluselementareOperationen (lesen, schreiben etc)
Elementare Aktionen
I Zeile vonstdinlesen:
getLine :: IO String
I Zeichenkette aufstdoutausgeben:
putStr :: String→ IO ()
I Zeichenkette mit Zeilenvorschubausgeben:
putStrLn :: String→ IO ()
Einfache Beispiele
I Echoeinfach echo1 :: IO ()
echo1 = getLine= putStrLn I Echomehrfach
echo :: IO ()
echo = getLine= putStrLn=λ_→ echo I Was passiert hier?
I Verknüpfenvon Aktionen mit=
I Jede Aktion gibtWertzurück
RP SS 2017 17 [36]
Noch ein Beispiel
I Umgekehrtes Echo:
ohce :: IO () ohce = getLine
=λs→ putStrLn ( reverse s )
>>ohce I Was passiert hier?
IReineFunktionreversewird innerhalb vonAktionputStrLngenutzt
IFolgeaktionohcebenötigtWertder vorherigen Aktion nicht
IAbkürzung:>>
p>>q = p=λ_→ q
RP SS 2017 18 [36]
Die do-Notation
I Syntaktischer Zucker fürIO:
echo = getLine
=λs→ putStrLn s
>>echo
⇐⇒
echo =
do s← getLine putStrLn s echo
I Rechts sind=,>>implizit.
I Es gilt dieAbseitsregel.
I Einrückungderersten Anweisungnachdobestimmt Abseits.
RP SS 2017 19 [36]
Drittes Beispiel
I Zählendes, endliches Echo echo3 :: Int→ IO () echo3 cnt =do
putStr (show cnt ++" : ") s← getLine
i f s6="" then do
putStrLn $ show cnt ++" : "++ s echo3 ( cnt+ 1)
else return () I Was passiert hier?
IKombinationausKontrollstrukturenundAktionen
IAktionenalsWerte
IGeschachteltedo-Notation
RP SS 2017 20 [36]
Ein/Ausgabe mit Dateien
I ImPreludevordefiniert:
I Dateien schreiben (überschreiben, anhängen):
type FilePath = String
w r i t e F i l e :: FilePath → String → IO () appendFile :: FilePath → String → IO () I Datei lesen (verzögert):
readFile :: FilePath →IO String
I Mehr Operationenim ModulSystem . IOder Standardbücherei
I Buffered/Unbuffered, Seeking, &c.
I Operationen aufHandle
I Noch mehr Operationen inSystem . Posix
I Filedeskriptoren, Permissions, special devices, etc.
RP SS 2017 21 [36]
Beispiel: Zeichen, Wörter, Zeilen zählen (wc)
wc :: String→ IO () wc f i l e =
docont ← readFile f i l e putStrLn $ f i l e ++" : "++
show ( length ( l i n e s cont ) , length (words cont ) , length cont ) I Datei wird gelesen
I Anzahl Zeichen, Worte, Zeilen gezählt I Erstaunlich (hinreichend) effizient
RP SS 2017 22 [36]
Aktionen als Werte
I AktionensindWertewie alle anderen.
I DadurchDefinitionvonKontrollstrukturenmöglich.
I Endlosschleife:
forever :: IOα→ IOα forever a = a>>forever a I Iteration (feste Anzahl):
forN :: Int→ IOα→IO () forN n a | n == 0 = return ()
| otherwise = a>>forN (n−1) a
Kontrollstrukturen
I VordefinierteKontrollstrukturen (Control .Monad):
when :: Bool→ IO ()→ IO () I Sequenzierung:
sequence :: [ IOα]→ IO [α]
ISonderfall:[ ( ) ]als() sequence_ :: [ IO () ]→IO () I Map und Filter für Aktionen:
mapM :: (α→IOβ)→ [α]→IO [β] mapM_ :: (α→IO () )→ [α]→IO ()
filterM :: (α→IO Bool) → [α] →IO [α]
Fehlerbehandlung
I Fehlerwerden durchExceptionrepräsentiert (Modul Control . Exception)
I ExceptionistTypklasse— kann durch eigene Instanzen erweitert werden
I Vordefinierte Instanzen: u.a.IOError
I FehlerbehandlungdurchAusnahmen(ähnlich Java) throw :: Exception γ=> γ→α
catch :: Exceptionγ=>IOα→ (γ→IOα) → IOα try :: Exception γ=>IOα→IO ( Either γ α) I Faustregel:catchfür unerwartete Ausnahmen,tryfür erwartete I Ausnahmen überall, Fehlerbehandlungnur in Aktionen
RP SS 2017 25 [36]
Fehler fangen und behandeln
I Fehlerbehandlung fürwc:
wc2 :: String→IO () wc2 f i l e =
catch (wc f i l e )
(λe→ putStrLn $ " Fehler : "++ show (e :: IOError ) )
I IOErrorkann analysiert werden (sieheSystem.IO.Error) I readmit Ausnahme bei Fehler (statt Programmabbruch):
readIO :: Read a=>String→IO a
RP SS 2017 26 [36]
Ausführbare Programme
I Eigenständiges Programm istAktion I Hauptaktion:main :: IO ()in ModulMain I wcals eigenständiges Programm:
moduleMain where
importSystem . Environment ( getArgs ) import Control . Exception
. . .
main :: IO () main =do
args← getArgs mapM_ wc2 args
RP SS 2017 27 [36]
Beispiel: Traversion eines Verzeichnisbaums
I Verzeichnisbaum traversieren, und für jede Datei eineAktion ausführen:
travFS :: ( FilePath→IO () )→ FilePath→ IO () I Nutzt Funktionalität ausSystem . Directory,System . FilePath travFS action p =do
res ← try ( getDirectoryContents p) case res of
Left e→ putStrLn $ "ERROR: "++ show (e :: IOError ) Right cs →do let cp = map (p</>) ( cs \\ [" . ", " . . "] )
d i r s ← filterM doesDirectoryExist cp f i l e s ← filterM doesFileExist cp mapM_ action f i l e s
mapM_ ( travFS action ) d i r s
RP SS 2017 28 [36]
So ein Zufall!
I Zufallswerte:
randomRIO :: (α,α)→ IOα
I Warum istrandomIOAktion?
I Beispiele:
I Aktion zufällig oft ausführen:
atmost :: Int→IOα→IO [α]
atmost most a =
dol←randomRIO (1 , most) sequence ( r e p l i c a t e l a)
I Zufälligen String erzeugen:
randomStr :: IO String
randomStr = atmost 40 (randomRIO ( ’ a ’ , ’ z ’ ) )
RP SS 2017 29 [36]
Module in der Standardbücherei
I Ein/Ausgabe, Fehlerbehandlung (ModulSystem . IO, Control . Exception)
I Zufallszahlen (ModulSystem .Random)
I Kommandozeile, Umgebungsvariablen (ModulSystem . Environment) I Zugriff auf das Dateisystem (ModulSystem . Directory)
I Zeit (ModulSystem .Time)
RP SS 2017 30 [36]
Fallbeispiel: Wörter raten
I Unterhaltungsprogramm: der Benutzer rät Wörter
I Benutzer kann einzelne Buchstaben eingeben oder das ganze Wort
I Wort wird maskiert ausgegeben, nur geratene Buchstaben angezeigt
Wörter raten: Programmstruktur
I Trennung zwischen Spiel-Logik und Nutzerschnittstelle I Spiel-Logik (GuessGame):
IProgrammzustand:
data State = St { word :: String−−Zu ratendes Wort , h i t s :: String−−Schon geratene Buchstaben , miss :: String−−Falsch geratene Buchstaben }
IInitialen Zustand (Wort auswählen):
i n i t i a l S t a t e :: [ String ]→IO State
INächsten Zustand berechnen (Charist Eingabe des Benutzers):
data Result = Miss | Hit | Repetition | GuessedIt | TooManyTries
processGuess :: Char→State→( Result , State )
Wörter raten: Nutzerschnittstelle
IHauptschleife (play)
I Zustand anzeigen
I Benutzereingabe abwarten
I Neuen Zustand berechnen
I Rekursiver Aufruf mit neuem Zustand
I Programmanfang (main)
I Lexikon lesen
I Initialen Zustand berechnen
I Hauptschleife aufrufen
play :: State→IO () play st =do
putStrLn ( render st ) c← getGuess st
case ( processGuess c st ) of ( Hit , st ) → play st
(Miss , st )→doputStrLn "Sorry , no . "; play st
( Repetition , st )→doputStrLn "You already t r i e d that . "; play st
( GuessedIt , st )→ putStrLn "Congratulations , you guessed i t . "
(TooManyTries , st )→
putStrLn $"The word was "++ word st ++"−−you lose . "
RP SS 2017 33 [36]
Kontrollumkehr
I Trennung von Logik (State,processGuess) und Nutzerinteraktion nützlich und sinnvoll
I Wird durch Haskell Tysystem unterstützt (keine UI ohneIO) I Nützlich für andere UI mitKontrollumkehr
I Beispiel: ein GUI für das Wörterratespiel (mit Gtk2hs)
IGUI ruft Handler-Funktionen des Nutzerprogramms auf
ISpielzustand in Referenz (IORef) speichern
I Vgl. MVC-Pattern (Model-View-Controller)
RP SS 2017 34 [36]
Eine GUI für das Ratespiel
I Bindenvon Funktionen anSignale
−−Process key presses
onKeyPress window $λe→case eventKeyChar e of Just c→dohandleKeyPress window l1 l2 gs c ; return
True
−−Process quit button
I Eventloop von Gtk2Hs aufrufen (Kontrollumkehr):
−−Run it!
onDestroy window mainQuit widgetShowAll window render st l1 l2
RP SS 2017 35 [36]
Zusammenfassung
I War das jetztreaktiv?
IHaskell istfunktional
IFür eine reaktive Sprache fehltNebenläufigkeit
I Nächstes Mal:
IMonaden, Ausnahmen, Referenzen in Haskell und Scala
I Danach: Nebenläufigkeit in Haskell und Scala
RP SS 2017 36 [36]