11.4 Die Ableitung regulärer Ausdrücke

Werbung
11 · Fallstudie: Reguläre Ausdrücke
11.4
�
1
2
Die Ableitung regulärer Ausdrücke · 11.4
Die Ableitung regulärer Ausdrücke
Das Wortproblem: Wir suchen eine Funktion, die den Input i gegen den
regulären Ausdruck r matcht:
match :: RegEx α -> [α] -> Bool
match r i = i ∈ L r — Pseudo-Code!
• Da L r potenziell unendlich ist,
scheidet explizites Aufzählen
aus.
Idee Wir zerlegen das Problem: Die Eingabe i hat die Form c : cs.
1. Können Worte in L r überhaupt mit c anfangen?
(Wenn nicht, sind wir fertig: i �∈ L r ⇒ match r i � False)
2. Wenn ja, welcher reguläre Ausdruck r � beschreibt die erlaubten Reste
aller Worte in L r die mit c anfangen?
3. Gilt cs ∈ L r � ? —Dieses Problem ist einfacher!
Notation
r � nennen wir die Ableitung von r nach c, und schreiben:
r � = ∂c r
Also muss gelten: L(∂c r ) = { cs | c:cs ∈ L r }.
Stefan Klinger · DBIS
Informatik 2 · Sommer 2016
362
11 · Fallstudie: Reguläre Ausdrücke
Die Ableitung regulärer Ausdrücke · 11.4
Was bleibt zu tun?
�
Wenn wir ∂c r für jedes Symbol c und jeden regulären Ausdruck r
berechnen können, ist das Wortproblem weitgehend gelöst. Denn z.B.
[c1 , c2 , c3 ] ∈ L r
�
�
[c2 , c3 ] ∈ L ∂c1 r
⇔
�
�
[c3 ] ∈ L ∂c2 (∂c1 r )
⇔
�
�
[ ] ∈ L ∂c3 (∂c2 (∂c1 r ))
⇔
�
Damit haben wir unser Problem gelöst, sofern wir nun noch entscheiden
können, ob ein regulärer Ausdruck die leere Eingabe [] akzeptiert.
Stefan Klinger · DBIS
Informatik 2 · Sommer 2016
363
11 · Fallstudie: Reguläre Ausdrücke
�
Die Ableitung regulärer Ausdrücke · 11.4
Diesen sogenannten nullable Test kann man tatsächlich sehr einfach
ausführen:
1
nullable :: RegEx α -> Bool
2
3
4
5
nullable RxNone
= False
nullable RxEpsilon = True
nullable (RxSym _) = False
— akzeptiert keine Eingabe, auch nicht die leere
— akzeptiert genau die leere Eingabe
— hier muss genau ein Buchstabe stehen
6
7
8
9
nullable (RxRep r)
=
nullable (RxSeq r s) =
nullable (RxAlt r s) =
?
?
?
Frage Wie lauten die fehlenden Gleichungen?
Stefan Klinger · DBIS
Informatik 2 · Sommer 2016
364
11 · Fallstudie: Reguläre Ausdrücke
�
Die Ableitung regulärer Ausdrücke · 11.4
Sei
derive :: Eq α ⇒ RegEx α → α → RegEx α
die Haskell-Implementation von ∂, also ∂x r = derive r x.
�
Dann ist match ein Einzeiler:
1
2
match :: Eq α => RegEx α -> [α] -> Bool
match r = nullable . foldl derive r
Fragen Warum fold-left?
Stefan Klinger · DBIS
Wofür wird Eq α benötigt?
Informatik 2 · Sommer 2016
365
11 · Fallstudie: Reguläre Ausdrücke
Die Ableitung regulärer Ausdrücke · 11.4
Beispiel
�
foldl
�
foldl
�
foldl
�
foldl
foldl derive r [c0 , c1 , c2 ]
foldl derive (r ‘derive‘ c0 ) [c1 , c2 ]
foldl derive ((r ‘derive‘ c0 ) ‘derive‘ c1 ) [c2 ]
foldl derive (((r ‘derive‘ c0 ) ‘derive‘ c1 ) ‘derive‘ c2 ) []
((r ‘derive‘ c0 ) ‘derive‘ c1 ) ‘derive‘ c2
Frage Verhält sich match r [] richtig, d.h. wird auch die leere Eingabe
korrekt gematcht?
Stefan Klinger · DBIS
Informatik 2 · Sommer 2016
366
11 · Fallstudie: Reguläre Ausdrücke
Die Ableitung regulärer Ausdrücke · 11.4
Die Ableitungsfunktion ∂
�
1
Es verbleibt die Implementation von derive:
derive :: Eq α => RegEx α -> α -> RegEx α
2
3
4
5
derive (RxSym c) x
| c == x
= rxEpsilon
— Hier brauchen wir Eq α
6
7
8
derive r@(RxRep s) x
= derive s x ‘rxSeq‘ r
9
10
11
derive (RxAlt r s) x
= derive r x ‘rxAlt‘ derive s x
12
13
14
15
16
17
derive (RxSeq r s) x
— Dies ist der einzige trickreiche Schritt
| nullable r
= (derive r x ‘rxSeq‘ s) ‘rxAlt‘ derive s x
| otherwise
= derive r x ‘rxSeq‘ s
�
18
19
20
derive _ _
= rxNone
Stefan Klinger · DBIS
— Alle anderen Fälle: ε, ∅, RxSym c | c�=x.
Informatik 2 · Sommer 2016
367
11 · Fallstudie: Reguläre Ausdrücke
Die Ableitung regulärer Ausdrücke · 11.4
Beispiel Die Ableitung derive implementiert tatsächlich unsere Idee (cf.
Seite 362, unten)
=
=
=
=
L (∂x ε)
=
{ cs | x:cs ∈ L ε }
=
{ cs | x:cs ∈ {[]} }
=
∅
=
L∅
=
=
=
=
=
Stefan Klinger · DBIS
L (∂x x)
{ cs | x:cs ∈ L x }
{ cs | x:cs ∈ {[x]} }
{[]}
Lε
L (∂x (r |s))
{ cs | x:cs ∈ L (r |s) }
{ cs | x:cs ∈ L r ∪ L s }
{ cs | x:cs ∈ L r } ∪ { cs | x:cs ∈ L s }
L (∂x r ) ∪ L (∂x s)
L (∂x r |∂x s)
Informatik 2 · Sommer 2016
368
11 · Fallstudie: Reguläre Ausdrücke
1
2
Die Ableitung regulärer Ausdrücke · 11.4
*Main> r
1, (eps | 1), (0, 0, (0, 0)*)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
*Main> derive it 1
— im GHCi ist it das Ergebnis der letzten Berechnung
(eps | 1), (0, 0, (0, 0)*)
*Main> derive it 0
0, (0, 0)*
*Main> derive it 0
(0, 0)*
*Main> derive it 1
{}
*Main> foldl derive r [1,0]
0, (0, 0)*
*Main> nullable it
False
17
18
19
20
21
*Main> foldl derive r [1,0,0]
(0, 0)*
*Main> nullable it
True
22
23
24
25
26
*Main> match r [0,1,0,1,0]
False
*Main> match r [1,1,0,0,0,0]
True
Stefan Klinger · DBIS
Informatik 2 · Sommer 2016
369
12
Lazy Evaluation
12 · Lazy Evaluation
�
Im λ-Kalkül ist die Reihenfolge der Reduktionsschritte (�) für einen
Ausdruck nicht a priori festgelegt.
�
Bisher haben wir nur intuitiv erklärt, wie lazy evaluation arbeitet:
Teilausdrücke werden erst bei Bedarf reduziert.
�
Im Folgenden werden wir genauer betrachten
• was das bedeutet (→ nicht-strikte Semantik),
• und wie das implementiert werden kann (→ Auswertestrategien).
Stefan Klinger · DBIS
Informatik 2 · Sommer 2016
371
12 · Lazy Evaluation
12.1
�
Strikte und nicht-strikte Semantik · 12.1
Strikte und nicht-strikte Semantik
Strikte Programmiersprachen beginnen die Auswertung eines Ausdrucks
bei der innersten Anwendung.
f (g x)
�
—zuerst wird g x reduziert
Nicht-strikte Sprachen fangen dagegen mit der äußersten Anwendung
an.
—zuerst wird f (...) reduziert
f (g x)
�
Wichtig Hier liegt ein semantischer Unterschied vor, d.h., strikte
und nicht-strikte Semantik ordnen dem gleichen Term unter Umständen
verschiedene Bedeutungen zu.
Stefan Klinger · DBIS
Informatik 2 · Sommer 2016
372
12 · Lazy Evaluation
Strikte und nicht-strikte Semantik · 12.1
Beispiel Sei g x = ⊥ eine nicht terminierende (oder undefinierte)
Berechnung, und sei f = λy . 3.
Der Term f (g x) hat unter...
... strikter Semantik den Wert ⊥, weil vor der Reduktion von f (...) das
Argument (endlos) reduziert wird.
... nicht-strikter Semantik den Wert 3, weil zuerst die Anwendung von f
reduziert wird: f (g x) = (λy . 3) (g x) � 3
β
Beispiele
�
Haskell hat nicht-strikte Semantik.
1
2
Prelude> take 10 [1..]
[1,2,3,4,5,6,7,8,9,10]
• Ebenso Miranda (ein direkter Haskell-Vorgänger) und Clean.
�
Die meisten Programmiersprachen sind jedoch strikt, z.B., C, Java, ML
(eine funktionale Sprache die starken Einfluss auf Haskell hatte).
Stefan Klinger · DBIS
Informatik 2 · Sommer 2016
373
12 · Lazy Evaluation
Strikte und nicht-strikte Semantik · 12.1
Definition Strikte Funktion
Eine Funktion f heisst strikt, genau dann wenn
x �⊥
f x �⊥
⇒
andernfalls heisst die Funktion nicht-strikt.
�
In einer strikten Programmiersprache sind alle Funktionen strikt.
• Im Gegensatz zu nicht-strikten Sprachen lässt sich das Konstrukt
if · then · else · fi nicht als Funktion :: Bool → α → α → α ausdrücken.
�
1
2
In einer nicht-strikten Sprache darf eine Funktion auch dann einen Wert
zurückgeben, wenn ihr Argument ⊥ ist.
Prelude> const 3 $ length [1..]
3
1
2
Prelude> const 3 undefined — ⊥
3
Das muss allerdings nicht für jede Funktion gelten, (1 +) ist z.B. strikt:
1
2
Prelude> 1 + length [1..]
— terminiert nicht
Stefan Klinger · DBIS
1
2
Prelude> 1 + undefined
*** Exception: Prelude.undefined
Informatik 2 · Sommer 2016
374
Herunterladen