• Keine Ergebnisse gefunden

Praktische Informatik 3: Funktionale Programmierung Vorlesung 6 vom 18.11.2014: Funktionen Höherer Ordnung II

N/A
N/A
Protected

Academic year: 2022

Aktie "Praktische Informatik 3: Funktionale Programmierung Vorlesung 6 vom 18.11.2014: Funktionen Höherer Ordnung II"

Copied!
5
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Praktische Informatik 3: Funktionale Programmierung Vorlesung 6 vom 18.11.2014: Funktionen Höherer Ordnung II

Christoph Lüth Universität Bremen Wintersemester 2014/15

Rev. 2776 1 [34]

Fahrplan

I Teil I: Funktionale Programmierung im Kleinen

IEinführung

IFunktionen und Datentypen

IRekursive Datentypen

ITypvariablen und Polymorphie

IFunktionen höherer Ordnung I

IFunktionen höherer Ordnung II

ITypinferenz

I Teil II: Funktionale Programmierung im Großen I Teil III: Funktionale Programmierung im richtigen Leben

2 [34]

Heute

I Die Geheimnisse vonmapundfoldrgelüftet.

I mapund foldrsind nicht nur für Listen.

I Funktionen höherer Ordnung als Entwurfsmuster

3 [34]

foldr ist kanonisch

I mapund filter sind durch foldrdarstellbar:

map :: (α→β)→ [α]→ [β] map f=f o l d r ( ( : ) . f ) [ ]

f i l t e r :: (α→ Bool)→ [α]→ [α]

f i l t e r p=f o l d r (λa as→ i f p a then a : as else as ) [ ]

foldrist diekanonische einfach rekursiveFunktion.

I Alle einfach rekursiven Funktionen sind als Instanz vonfoldr darstellbar.

foldr (:) [ ]=id

4 [34]

map als strukturerhalten Abbildung

mapist die kanonischestrukturerhaltende Abbildung.

I Struktur(Shape) eines Datentyps Tαist T().

I Für jeden Datentyp kann man kanonische Funktionshape:: Tα→T () angeben

I Für Listen: [()]∼=Nat.

I Fürmapgelten folgende Aussagen:

map id=id map f◦map g=map (f◦g)

shape. map f=shape

5 [34]

Grenzen von foldr

I Andere rekursive Struktur über Listen

IQuicksort:baumartigeRekursion qsort :: Ord a⇒ [ a ]→ [ a ] qsort [ ]= [ ]

qsort xs=qsort ( f i l t e r (<head xs ) xs ) ++ f i l t e r (head xs==) xs ++ qsort ( f i l t e r (head xs<) xs ) I Rekursion nicht über Listenstruktur:

I take: Rekursion überInt take :: Int→ [ a ]→ [ a ] take n _ | n≤0= [ ]

take _ [ ] = [ ]

take n (x : xs ) = x : take (n−1) xs

IVersion mitfoldr divergiert für nicht-endliche Listen

6 [34]

fold für andere Datentypen

foldist universell

Jeder algebraische Datentyp T hat genau einfoldr. I Kanonische Signatur fürT:

I Pro KonstruktorCein FunktionsargumentfC I Freie TypvariableβfürT

I Kanonische Definition:

I Pro KonstruktorCeine Gleichung

I Gleichung wendet FunktionsparameterfCauf Argumente an

data IL=Cons Int IL | Err String | Mt

f ol dIL :: ( Int→β→β)→ ( String→β)→β→ IL→β f ol dIL f e a (Cons i i l )=f i ( f old IL f e a i l ) f ol dIL f e a ( Err s t r ) =e s t r

f ol dIL f e a Mt =a

fold für bekannte Datentypen

I Bool: Fallunterscheidung:

dataBool=True | False foldBool :: β→β→Bool→β foldBool a1 a2 True =a1 foldBool a1 a2 False=a2 I Maybe a: Auswertung

dataMaybeα=Nothing | Justα foldMaybe :: β→ (α→β)→Maybeα→β foldMaybe b f Nothing =b

foldMaybe b f ( Just a)=f a

IAlsmaybevordefiniert

(2)

fold für bekannte Datentypen

I Tupel: dieuncurry-Funktion

foldPair :: (α→β→γ)→ (α, β)→γ foldPair f (a , b)=f a b

I Natürliche Zahlen: Iterator dataNat=Zero | Succ Nat foldNat :: β→ (β→β)→Nat→β foldNat e f Zero =e

foldNat e f (Succ n)=f ( foldNat e f n)

9 [34]

fold für binäre Bäume

I Binäre Bäume:

dataTreeα=Mt | Nodeα (Treeα) (Treeα)

ILabelnurin den Knoten I Instanzen von Map und Fold:

mapT :: (α→β)→Treeα→ Treeβ mapT f Mt=Mt

mapT f (Node a l r )=

Node ( f a) (mapT f l ) (mapT f r ) foldT :: (α→β→β→β)→β→ Treeα→β foldT f e Mt=e

foldT f e (Node a l r )= f a ( foldT f e l ) ( foldT f e r )

IKein (offensichtliches) Filter

10 [34]

Funktionen mit fold und map

I Höhe des Baumes berechnen:

height :: Treeα→ Int

height=foldT (λ_ l r→1+max l r ) 0

I Inorder-Traversion der Knoten:

inorder :: Treeα→ [α]

inorder=foldT (λa l r→ l++ [ a ]++r ) [ ]

11 [34]

Kanonische Eigenschaften von foldT und mapT

I Auch hier gilt:

foldTree Node Mt=id mapTree id=id

mapTree f◦mapTree g=mapTree (f◦g) shape (mapTree f xs)=shape xs

I Mitshape :: Treeα→Tree ()

12 [34]

Das Labyrinth

I Das Labyrinth als variadischer Baum:

dataVTreeα=Nodeα [ VTreeα]

typeLabα=VTreeα

I Auch hierfürfoldTundmapT:

foldT :: (α→ [β]→β)→VTreeα→β foldT f (Node a ns )=f a (map ( foldT f ) ns ) mapT :: (α→β)→ VTreeα→VTreeβ

mapT f (Node a ns )=Node ( f a) (map (mapT f ) ns )

13 [34]

Suche im Labyrinth

I Tiefensuche viafoldT dfts ’ :: Labα→ [ Pathα]

dfts ’ =foldT addwhere add a [ ]=[ [ a ] ]

add a ps=concatMap (map (a : ) ) ps I Problem:

I foldTterminiertnichtfürzyklischeStrukturen

IAuch nicht, wennaddprüft obaschon enthalten ist

IPfade werden vomEndekonstruiert

14 [34]

Alternativen: Breitensuche

I Alternative 1:Tiefensuchedirekt rekursiv, mitTerminationsprädikat dfts :: Eqα⇒ (Labα→ Bool)→Labα→ [ Pathα]

I Alternative 2: Breitensuche fürpotentiell unendlicheListeallerPfade bfts :: Labα→ [ Pathα]

bfts l =bfts0 [ ] [ l ] where bfts0 p [ ]=[ ]

bfts0 p (Node a cs : ns)=

reverse (a : p) : ( bfts0 p ns++ bfts0 (a : p) cs )

I Gegensatz zur Tiefensuche: Liste kannkonsumiertwerden

15 [34]

Zusammenfassung map und fold

I mapundfoldsindkanonischeFunktionen höherer Ordnung I Für jeden Datentyp definierbar

I foldl nur für Listen (linearerDatentyp)

I foldkann beizyklischenArgumenten nicht terminieren

IProblem: Termination vonfoldnurlokalentscheidbar

IIm Labyrinth braucht man denKontextum zu entscheiden ob ein Knoten ein Blatt ist

16 [34]

(3)

Funktionen Höherer Ordnung als Entwurfsmethodik

I Kombinationvon Basisoperationen zu komplexen Operationen I KombinatorenalsMusterzur Problemlösung:

I EinfacheBasisoperationen

I WenigeKombinationsoperationen

I Alle anderen Operationenabgeleitet I Kompositionalität:

I Gesamtproblem läßt sichzerlegen

I Gesamtlösung durchZusammensetzender Einzellösungen

17 [34]

Kombinatoren im engeren Sinne

Definition (Kombinator)

EinKombinatorist ein punktfrei definierte Funktion höherer Ordnung.

I Herkunft:Kombinatorlogik(Schönfinkel, 1924)

K x y B x S x y z B x z(y z)

I x B x

S,K,IsindKombinatoren

I Fun fact #1: kann alle berechenbaren Funktionen ausdrücken I Fun fact #2:SundKsind genug:I=S K K

18 [34]

Beispiel: Parser

I Parserbilden Eingabe auf Parsierungen ab

I Mehrere Parsierungenmöglich

I Backtrackingmöglich I Kombinatoransatz:

I BasisparsererkennenTerminalsymbole

I Parserkombinatorenzur Konstruktion:

I Sequenzierung(erstA, dannB)

I Alternierung(entwederAoderB)

I AbgeleiteteKombinatoren (z.B.ListenA,nicht-leereListenA+)

19 [34]

Modellierung in Haskell

WelcherTypfür Parser?

typeParseα β=[α]→[(β, [α])]

I Parametrisiert überEingabetyp(Token)αundErgebnisβ I Parser übersetztTokeninErgebnis(abstrakte Syntax) I MussRest der Eingabemodellieren

I Mussmehrdeutige Ergebnissemodellieren

I Beispiel:"4*5+3"→[ (4,"*4+3"), (4*5,"+3"), (4*5+3,"")]

20 [34]

Basisparser

I Erkenntnichts:

none :: Parseα β none=const [ ] I Erkenntalles:

suceed :: β→ Parseα β suceed b inp=[ ( b , inp ) ] I Erkennteinzelne Token:

spot :: (α→ Bool)→ Parseα α spot p [ ] = [ ]

spot p (x : xs )=i f p x then [ ( x , xs ) ] else [ ] token :: Eqα⇒α→ Parseα α

token t=spot ( t==)

I Warum nichtnone,suceeddurchspot? Typ!

21 [34]

Basiskombinatoren: alt , >∗>

I Alternierung:

IErste Alternative wirdbevorzugt i n f i x l 3 ‘ alt ‘

a l t :: Parseα β→ Parseα β→ Parseα β a l t p1 p2 i=p1 i ++p2 i

I Sequenzierung:

IRest des ersten Parsers alsEingabefür den zweiten i n f i x l 5>∗>

(>∗>) :: Parseα β→ Parseα γ→ Parseα (β, γ) (>∗>) p1 p2 i =

concatMap (λ(b , r )→

map (λ(c , s )→ ((b , c ) , s )) (p2 r )) (p1 i )

22 [34]

Basiskombinatoren: use

I mapfür Parser (Rückgabeweiterverarbeiten):

i n f i x 4 ‘ use ‘ , ‘ use2 ‘

use :: Parseα β→ (β→γ)→Parseα γ use p f i=map (λ(o , r )→ ( f o , r )) (p i ) use2 :: Parseα(β, γ)→ (β→γ→ δ)→ Parseα δ use2 p f =use p ( uncurry f )

I Damit z.B. Sequenzierungrechts/links:

i n f i x l 5 ∗>,>

(∗>) :: Parseα β→ Parseα γ→ Parseα γ (>∗) :: Parseα β→ Parseα γ→ Parseα β p1 ∗>p2=p1>∗>p2 ‘ use ‘ snd

p1>∗ p2=p1>∗>p2 ‘ use ‘ f s t

Abgeleitete Kombinatoren

I Listen: A::=AA|ε l i s t :: Parseα β→ Parseα [β]

l i s t p=p>∗>l i s t p ‘ use2 ‘ ( : )

‘ alt ‘ suceed [ ]

I Nicht-leereListen: A+::=AA some :: Parseα β→ Parseα [β]

some p=p>∗>l i s t p ‘ use2 ‘ ( : )

I NB. Präzedenzen:>∗>(5) voruse(4) voralt(3)

(4)

Verkapselung

I Hauptfunktion:

I Eingabe mußvollständigparsiert werden

I AufMehrdeutigkeitprüfen

parse :: Parseα β→ [α]→ Either Stringβ parse p i=

case f i l t e r ( n u l l . snd) $ p i of [ ] → Left "Input␣does␣not␣parse "

[ ( e , _) ] → Right e

_ → Left "Input␣ i s ␣ambiguous"

I Schnittstelle:

I Nach außen nur TypParsesichtbar, plusOperationendarauf

25 [34]

Grammatik für Arithmetische Ausdrücke

Expr ::= Term+Term|Term Term ::= Factor*Factor|Factor Factor ::= Variable|(Expr) Variable ::= Char+

Char ::= a| · · · |z|A| · · · |Z

26 [34]

Abstrakte Syntax für Arithmetische Ausdrücke

I Zur Grammatikabstrakte Syntax data Expr =Plus Expr Expr

| Times Expr Expr

| Var String

I Hier UnterscheidungTerm,Factor,Numberunnötig.

27 [34]

Parsierung Arithmetischer Ausdrücke

I Token:Char I Parsierung vonFactor

pFactor :: Parse Char Expr

pFactor=some ( spot isAlpha ) ‘ use ‘ Var

‘ alt ‘ token ’ ( ’ ∗>pExpr>∗ token ’ ) ’ I Parsierung vonTerm

pTerm :: Parse Char Expr pTerm=

pFactor>∗ token ’∗’>∗>pFactor ‘ use2 ‘ Times

‘ alt ‘ pFactor I Parsierung vonExpr

pExpr :: Parse Char Expr

pExpr=pTerm>∗ token ’+’>∗>pTerm ‘ use2 ‘ Plus

‘ alt ‘ pTerm

28 [34]

Die Hauptfunktion

I Lexing:Leerzeichenaus der Eingabeentfernen parseExpr :: String→ Expr

parseExpr i=

case parse pExpr ( f i l t e r (not . isSpace ) i ) of Right e→ e

Left e r r → er ro r e r r

29 [34]

Ein kleiner Fehler

I Mangel:a+b+cführt zuSyntaxfehler— Fehler in derGrammatik I Behebung:Änderungder Grammatik

Expr ::= Term+Expr|Term Term ::= Factor*Term|Factor Factor ::= Variable|(Expr) Variable ::= Char+

Char ::= a| · · · |z|A| · · · |Z

I Abstrakte Syntaxbleibt

30 [34]

Änderung des Parsers

I Entsprechende Änderung des Parsers inpTerm pTerm :: Parse Char Expr

pTerm=

pFactor>∗ token ’∗’>∗>pTerm ‘ use2 ‘ Times

‘ alt ‘ pFactor I . . . und inpExpr:

pExpr :: Parse Char Expr

pExpr=pTerm>∗ token ’+’>>pExpr ‘ use2 ‘ Plus

‘ alt ‘ pTerm

I pFactorund Hauptfunktion bleiben.

31 [34]

Erweiterung zu einem Taschenrechner

I Zahlen:

Factor ::= Variable|Number|. . . Number ::= Digit+

Digit ::= 0| · · · |9 I Eine einfacheEingabesprache:

Input ::= !Variable=Expr|$Expr I EineAuswertungsfunktion:

type State=[ ( String , Integer ) ] eval :: State→Expr→ Integer run :: State→ String→ ( State , String )

32 [34]

(5)

Zusammenfassung Parserkombinatoren

I Systematische Konstruktiondes Parsers aus der Grammatik.

I Kompositional:

I Lokale Änderung der Grammatik führt zu lokaler Änderung im Parser

I Vgl. Parsergeneratoren (yacc/bison, antlr, happy)

I Struktur vonParsezur Benutzung irrelevant

I Vorsicht beiMehrdeutigkeitenin der Grammatik (Performance-Falle)

I Einfache Implementierung(wie oben) skaliertnicht

I Effiziente Implementation mitgleicher Schnittstelleauch fürgroße Eingabengeeignet.

33 [34]

Zusammenfassung

I mapundfoldsind kanonische Funktionen höherer Ordnung I . . . und für alle Datentypen definierbar

I Kombinatoren: Funktionen höherer Ordnung alsEntwurfsmethodik

IEinfacheBasisoperationen

IWenigeabermächtigeKombinationsoperationen

IReiche Bibliothek anabgeleitetenOperationen I Nächste Woche: wie prüft man den Typ von

(>∗>) p1 p2 i = concatMap (λ(b , r )→

map (λ(c , s )→ ((b , c ) , s )) (p2 r )) (p1 i )

→Typinferenz!

34 [34]

Referenzen

ÄHNLICHE DOKUMENTE

I Für funktionale Programme: rekursiv definierte Funktionen.. Äquivalenz von operationaler und

Praktische Informatik 3: Funktionale Programmierung Vorlesung 5 vom 15.11.2016: Funktionen Höherer Ordnung I..

I Striktheit: Speicherlecks vermeiden (bei verzögerter Auswertung) I Vorteil: Effizienz muss nicht im Vordergrund stehen. PI3 WS 16/17

Praktische Informatik 3: Funktionale Programmierung Vorlesung 2 vom 21.10.2014: Funktionen und Datentypen..

Praktische Informatik 3: Funktionale Programmierung Vorlesung 5 vom 11.11.2014: Funktionen Höherer Ordnung I..

Praktische Informatik 3: Funktionale Programmierung Vorlesung 5 vom 11.11.2014: Funktionen Höherer Ordnung I.. Christoph Lüth Universität Bremen

Praktische Informatik 3: Funktionale Programmierung Vorlesung 6 vom 18.11.2014: Funktionen Höherer Ordnung II..

konstanter Aufwand ←→ beliebige Genauigkeit, wachsender Aufwand Haskell bietet die Auswahl:. I Int - ganze Zahlen als Maschinenworte (≥