Praktische Informatik 3: Einführung in die Funktionale Programmierung
Vorlesung vom 12.01.2011: Aktionen und Zustände
Christoph Lüth & Dennis Walter Universität Bremen Wintersemester 2010/11
Rev. 1312 1 [26]
Fahrplan
I Teil I: Funktionale Programmierung im Kleinen
I Teil II: Funktionale Programmierung im Großen
IAbstrakte Datentypen
ISignaturen und Eigenschaften
IAktionen und Zustände
I Teil III: Funktionale Programmierung im richtigen Leben
2 [26]
Inhalt
IEin/Ausgabe in funktionale Sprachen
IWo ist dasProblem?
IAktionenund der DatentypIO.
IAktionenalsWerte
IAktionenalsZustandstransformationen
3 [26]
Ein- und Ausgabe in funktionalen Sprachen
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“
4 [26]
Aktionen als abstrakter Datentyp
IADT mit OperationenKompositionundLifting
ISignatur:
type IO α
(=) :: IO α → (α→ IO β) → IO β
r e t u r n :: α→ IO α
IPluselementareOperationen (lesen, schreiben etc)
5 [26]
Elementare Aktionen
I Zeile vonstdinlesen:
g e t L i n e :: IO S t r i n g
I Zeichenkette aufstdoutausgeben:
p u t S t r :: S t r i n g→ IO ( )
I Zeichenkette mit Zeilenvorschubausgeben:
p u t S t r L n :: S t r i n g→ IO ( )
6 [26]
Einfache Beispiele
IEchoeinfach e c h o 1 :: IO ( )
e c h o 1 = g e t L i n e =p u t S t r L n IEchomehrfach
e c h o :: IO ( )
e c h o = g e t L i n e=p u t S t r L n=λ_ → e c h o IWas passiert hier?
IVerknüpfenvon Aktionen mit=
IJede Aktion gibtWertzurück
7 [26]
Noch ein Beispiel
I Umgekehrtes Echo:
o h c e :: IO ( ) o h c e = g e t L i n e
=λs→ p u t S t r L n ( r e v e r s e s ) o h c e
I Was passiert hier?
IReineFunktionreversewird innerhalb vonAktionputStrLngenutzt
IFolgeaktionohcebenötigtWertder vorherigen Aktion nicht
IAbkürzung:
pq =p=λ_ → q
8 [26]
Die do-Notation
ISyntaktischer Zucker fürIO:
e c h o = g e t L i n e
=λs→ p u t S t r L n s e c h o
⇐⇒
e c h o =
do s← g e t L i n e p u t S t r L n s e c h o
IRechts sind=,implizit.
IEs gilt dieAbseitsregel.
IEinrückungderersten Anweisungnachdobestimmt Abseits.
9 [26]
Drittes Beispiel
I Zählendes, endliches Echo e c h o 3 :: I n t→ IO ( ) e c h o 3 c n t = do
p u t S t r ( show c n t ++ " : " ) s← g e t L i n e
i f s /= " " then do
p u t S t r L n $ show c n t ++ " : "++ s e c h o 3 ( c n t+ 1 )
e l s e r e t u r n ( ) I Was passiert hier?
IKombinationausKontrollstrukturenundAktionen
IAktionenalsWerte
IGeschachteltedo-Notation
10 [26]
Module in der Standardbücherei
IEin/Ausgabe, Fehlerbehandlung (ModulIO) IZufallszahlen (ModulRandom)
IKommandozeile, Umgebungsvariablen (ModulSystem)
IZugriff auf das Dateisystem (ModulDirectory)
IZeit (ModulTime)
11 [26]
Ein/Ausgabe mit Dateien
I ImPreludevordefiniert:
IDateien schreiben (überschreiben, anhängen):
type F i l e P a t h = S t r i n g
w r i t e F i l e :: F i l e P a t h → S t r i n g → IO ( ) a p p e n d F i l e :: F i l e P a t h → S t r i n g → IO ( ) I Datei lesen (verzögert):
r e a d F i l e :: F i l e P a t h → IO S t r i n g I Mehr Operationenim ModulIOder Standardbücherei
IBuffered/Unbuffered, Seeking, &c.
IOperationen aufHandle
12 [26]
Beispiel: Zeichen, Wörter, Zeilen zählen (wc)
wc :: S t r i n g→ IO ( ) wc f i l e =
do c o n t ← r e a d F i l e f i l e p u t S t r L n $ f i l e++ " : "++
show ( l e n g t h ( l i n e s c o n t ) , l e n g t h ( w o r d s c o n t ) , l e n g t h c o n t )
INicht sehr effizient — Datei wirdim Speicher gehalten.
13 [26]
Beispiel: wc verbessert.
I Effizienter: Dateiinhalteinmaltraversieren c n t :: I n t→ I n t→ I n t→ B o o l→ S t r i n g
→ ( I n t , I n t , I n t ) c n t l w c _ [ ] = ( l , w , c ) c n t l w c b l ( x : x s )
| i s S p a c e x && n o t b l = c n t l ’ (w+1 ) ( c+1 ) True x s
| i s S p a c e x && b l = c n t l ’ w ( c+1 ) True x s
| o t h e r w i s e = c n t l w ( c+1 ) F a l s e x s where l ’ = i f x == ’ \n ’ then l+1 e l s e l
I Hauptprogramm:
wc :: S t r i n g→ IO ( ) wc f i l e = do
c o n t ← r e a d F i l e f i l e
p u t S t r L n $ f i l e++ " : "++ show ( c n t 0 0 0 F a l s e c o n t ) I Datei wirdverzögert gelesenunddabei verbraucht.
14 [26]
Aktionen als Werte
IAktionensindWertewie alle anderen.
IDadurchDefinitionvonKontrollstrukturenmöglich.
IEndlosschleife:
f o r e v e r :: IO α→ IO α f o r e v e r a = a f o r e v e r a IIteration (feste Anzahl):
f o r N :: I n t→ IO α→ IO ( ) f o r N n a | n == 0 = r e t u r n ( )
| o t h e r w i s e = a f o r N ( n−1) a IVordefinierteKontrollstrukturen (Control.Monad):
Iwhen,mapM,forM,sequence, . . .
15 [26]
Fehlerbehandlung
I Fehlerwerden durchIOErrorrepräsentiert
I FehlerbehandlungdurchAusnahmen(ähnlich Java) i o E r r o r :: I O E r r o r → IO α −−"throw"
c a t c h :: IO α→ ( I O E r r o r→ IO α) → IO α
I Fehlerbehandlungnur in Aktionen
16 [26]
Fehler fangen und behandeln
IFehlerbehandlung fürwc:
wc2 :: S t r i n g→ IO ( ) wc2 f i l e =
c a t c h ( wc f i l e )
(λe→ p u t S t r L n $ " F e h l e r : "++ show e )
IIOErrorkann analysiert werden (siehe ModulIO) Ireadmit Ausnahme bei Fehler (statt Programmabbruch):
r e a d I O :: Read a⇒ S t r i n g→ IO a
17 [26]
So ein Zufall!
I Zufallswerte:
randomRIO :: (α, α)→ IO α
IWarum istrandomIOAktion?
I Beispiel:Aktionen zufällig oft ausführen a t m o s t :: I n t→ IO α→ IO [α]
a t m o s t most a =
do l← randomRIO ( 1 , most ) mapM i d ( r e p l i c a t e l a ) I Zufälligen String erzeugen
r a n d o m S t r :: IO S t r i n g
r a n d o m S t r = a t m o s t 40 ( randomRIO ( ’ a ’ , ’ z ’ ) )
18 [26]
Ausführbare Programme
IEigenständiges Programm istAktionen
IHauptaktion:mainin ModulMain Iwcals eigenständiges Programm:
module Main where
import System . E n v i r o n m e n t ( g e t A r g s ) import Char ( i s S p a c e )
main =do
a r g s ← g e t A r g s mapM wc2 a r g s
19 [26]
Funktionen mit Zustand
Theorem (Currying) Folgende Typen sindisomorph:
A×B→C∼=A→B→C
I In Haskell: folgende Funktionen sindinvers:
c u r r y :: ( (α, β) → γ)→ α→ β→ γ u n c u r r y :: (α→ β→ γ)→ (α, β) → γ
20 [26]
Funktionen mit Zustand
IIdee: Seiteneffektexplizitmachen
IFunktionf :A→Bmit Seiteneffekt inZustandS:
f :A×S→B×S
∼= f :A→S→B×S
IDatentyp:S→B×S
IKomposition: Funktionskomposition unduncurry
21 [26]
In Haskell: Zustände explizit
I Datentyp: Berechnung mit Seiteneffekt in TypΣ:
type S t a t e Σ α= Σ→ (α, Σ)
I Komposition zweier solcher Berechnungen:
comp :: S t a t e Σ α→ (α→ S t a t e Σβ)→ S t a t e Σ β comp f g = u n c u r r y g◦ f
I Lifting:
l i f t :: α→ S t a t e Σ α l i f t = c u r r y i d
22 [26]
Beispiel: Ein Zähler
IDatentyp:
type W i t h C o u n t e r α= S t a t e I n t α IZähler erhöhen:
t i c k :: W i t h C o u n t e r ( ) t i c k i = ( ( ) , i+1 ) IZähler auslesen:
r e a d :: W i t h C o u n t e r I n t r e a d i = ( i , i )
IZähler zurücksetzen:
r e s e t :: W i t h C o u n t e r ( ) r e s e t i = ( ( ) , 0 )
23 [26]
Implizite vs. explizite Zustände
I Nachteil: Zustand istexplizit
IKanndupliziertwerden
I Daher: Zustandimplizitmachen
IDatentypverkapseln
ISignaturState , comp, lift, elementare Operationen
24 [26]
Aktionen als Zustandstransformationen
IIdee: Aktionen sindTransformationenauf SystemzustandS ISbeinhaltet
ISpeicher als AbbildungA*V(AdressenA, WerteV)
IZustand des Dateisystems
IZustand des Zufallsgenerators
IIn Haskell: TypRealWorld
I“Virtueller” Typ, Zugriff nur über elementare Operationen
IEntscheidend nurReihenfolgeder Aktionen
25 [26]
Zusammenfassung
I Ein/Ausgabe in Haskell durchAktionen
I Aktionen(TypIOα) sind seiteneffektbehaftete Funktionen I Kompositionvon Aktionen durch
(=) :: IO α→ (α→ IO β)→ IO β
r e t u r n :: α→ IO α I do-Notation
I Fehlerbehandlung durch Ausnahmen (IOError,catch).
I Verschiedene Funktionen der Standardbücherei:
IPrelude:getLine,putStr,putStrLn,readFile, writeFile
IModule:IO,Random
I Aktionen sindimplementiertalsZustandstransformationen
26 [26]