Funktionale Programmierung

Werbung
Parser in Haskell
Funktionale Programmierung
Parser
D. Rösner
Institut für Wissens- und Sprachverarbeitung
Fakultät für Informatik
Otto-von-Guericke Universität Magdeburg
c
Sommer 2013, 6. Juni 2013, 2011-13
D.Rösner
D. Rösner FP 2013 . . .
1
Parser in Haskell
Gliederung
1
Parser in Haskell
. . . als Funktionen
. . . als Monaden
D. Rösner FP 2013 . . .
2
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Eine Bibliothek von Bausteinen für Parser
Grundidee (vgl. [Thompson 17.5]):
Parser als Funktionen
Kombinatoren für Parser als Funktionen höherer Ordnung
Polymorphismus
D. Rösner FP 2013 . . .
4
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Eine Bibliothek von Bausteinen für Parser
token . . . ein Parser, der in der Eingabeliste ein spezielles
erstes Element – ein Token – erwartet und im Erfolgsfall
dieses Token ’konsumiert’
>token :: Eq a => a -> Parse a a
>token t (x:xs)
> | t==x
= [(t,xs)]
> | otherwise = []
>token t [] = []
D. Rösner FP 2013 . . .
5
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Eine Bibliothek von Bausteinen für Parser
spot . . . Verallgemeinerung von token; ein Parser, der ein
erstes Element in der Eingabeliste mit einer speziellen
Eigenschaft ’konsumiert’
>spot :: (a -> Bool) -> Parse a a
>spot p (x:xs)
> | p x
= [(x,xs)]
> | otherwise = []
>spot p [] = []
D. Rösner FP 2013 . . .
6
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Eine Bibliothek von Bausteinen für Parser
die beiden elementaren Parser none bzw. succeed sind
Sonderfälle, die beide nichts konsumieren
none . . . schlägt dabei immer fehl
>none :: Parse a b
>none inp = []
succeed . . . ist immer erfolgreich mit einem als Parameter
übergebenen Rückgabewert
>succeed :: b -> Parse a b
>succeed val inp = [(val,inp)]
D. Rösner FP 2013 . . .
7
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Bibliothek für Parser: Kombinatoren
Alternative Parser lassen sich mit alt zu einem Parser
vereinen, der die Ergebnisse der Alternativen in einer
Ergebnisliste vereint
>alt :: Parse a b -> Parse a b -> Parse a b
>
>alt p1 p2 inp = p1 inp ++ p2 inp
D. Rösner FP 2013 . . .
8
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Bibliothek für Parser: Kombinatoren
Damit Parser so aneinandergefügt werden können, dass
der zweite mit dem Teil der ursprünglichen Eingabe
weiterarbeitet, der beim ersten Parser übrigblieb,
definieren wir den Operator >*>:
>infixr 5 >*>
>(>*>) :: Parse a b -> Parse a c -> Parse a (b,c)
>(>*>) p1 p2 inp
> = [((y,z),rem2)|(y,rem1) <- p1 inp, (z,rem2) <- p2 rem1]
D. Rösner FP 2013 . . .
9
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Bibliothek für Parser: Kombinatoren
build erlaubt, einen Parser vom Typ Parse a c mit
Ergebnistyp c dadurch zu ’bauen’, dass auf das Ergebnis
(vom Typ b) eines Parser vom Typ Parse a b eine
Funktion vom Typ b -> c angewendet wird
>build
:: Parse a b -> (b -> c) -> Parse a c
>build p f inp = [(f x,rem)|(x,rem) <- p inp]
D. Rösner FP 2013 . . .
10
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Bibliothek für Parser: Kombinatoren
list erlaubt es, aus einem Parser für ein bestimmtes
Objekt einen Parser zu kombinieren, der Listen solcher
Objekte erkennen kann
>list :: Parse a b -> Parse a [b]
>list p = (succeed [])
>
‘alt‘
>
((p >*> list p) ‘build‘ (uncurry (:)))
auch der Spezialfall einer leeren Liste ist zugelassen.
Diese wird vom Parser (succeed []) verarbeitet.
D. Rösner FP 2013 . . .
11
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser
Quelle:
A HASKELL LIBRARY OF MONADIC PARSER COMBINATORS
17th April 1997
Graham Hutton
University of Nottingham
Erik Meijer
University of Utrecht
definiert wird eine Sammlung monadischer Kombinatoren
für Parser
genutzt für zeichenweise arbeitende Parser
Verallgemeinerung möglich
D. Rösner FP 2013 . . .
13
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser
der Typ:
newtype Parser a = Parser (String -> [(a,String)])
die Monade:
instance Monad Parser where
return a = Parser (\cs -> [(a,cs)])
p >>= f
= Parser (\cs -> concat [parse (f a) cs’ |
(a,cs’) <- parse p cs])
D. Rösner FP 2013 . . .
14
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser
zusätzlich Parser als Instanz von MonadPlus:
instance MonadPlus Parser where
mzero
= Parser (\cs -> [])
p ‘mplus‘ q = Parser (\cs -> parse p cs ++ parse q cs)
mzero . . . Parser, der immer fehlschlägt
‘mplus‘ . . . vereinige die Ergebnisse alternativer Parser
D. Rösner FP 2013 . . .
15
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser
der zugehörige Dekonstruktor
parse :: Parser a -> String -> [(a,String)]
parse (Parser p) = p
D. Rösner FP 2013 . . .
16
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser
item . . . akzeptiert das erste Zeichen eines nichtleeren
String
item :: Parser Char
item = Parser (\cs -> case cs of
""
-> []
(c:cs) -> [(c,cs)])
D. Rösner FP 2013 . . .
17
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser
sat . . . akzeptiert das erste Zeichen eines nichtleeren
String, wenn dieses einer Bedingung p genügt
sat :: (Char -> Bool) -> Parser Char
sat p = do c <- item
if p c then return c else mzero
D. Rösner FP 2013 . . .
18
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser: Beispiele
char c . . . akzeptiert genau das Zeichen c
char :: Char -> Parser Char
char c = sat (c ==)
digit . . . akzeptiert eine Ziffer und gibt ihren Wert als
Integer zurück
digit :: Parser Int
digit = do {c <- sat isDigit;
return (ord c - ord ’0’)}
D. Rösner FP 2013 . . .
19
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser
string . . . nimmt einen String und liefert einen Parser, der
genau diesen akzeptiert
string :: String -> Parser String
string "" = return ""
string (c:cs)
= do {char c; string cs; return (c:cs)}
D. Rösner FP 2013 . . .
20
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser: Kombinatoren
(+++) . . . zwei Parser werden so kombiniert, dass die
Kombination fehlschlägt, wenn beide fehlschlagen und
andernfalls das erste Resultat zurückgegeben wird
(+++)
:: Parser a -> Parser a -> Parser a
p +++ q = Parser (\cs -> case parse (p ‘mplus‘ q) cs of
[]
-> []
(x:xs) -> [x])
D. Rösner FP 2013 . . .
21
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser: Kombinatoren
force . . .
force :: Parser a -> Parser a
force p =
Parser (\cs -> let xs = parse p cs in
(fst (head xs), snd (head xs)) : tail xs)
D. Rösner FP 2013 . . .
22
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser: Kombinatoren
many p . . . Parser, der null oder mehrere erfolgreiche
Anwendungen des Parsers p akzeptiert; zurückgegeben
wird der längste erfolgreiche Match
many :: Parser a -> Parser [a]
many p = force (many1 p +++ return [])
many1 p . . . Parser, der ein oder mehrere erfolgreiche
Anwendungen des Parsers p akzeptiert; zurückgegeben
wird der längste erfolgreiche Match
many1 :: Parser a -> Parser [a]
many1 p = do {a <- p; as <- many p; return (a:as)}
D. Rösner FP 2013 . . .
23
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser: Kombinatoren
sepby p sep . . . kombiniert Parser p und Parser sep so,
dass ein Parser entsteht,
der null oder mehrere erfolgreiche Anwendungen des
Parser p akzeptiert,
zwischen denen jeweils (als Separator) eine erfolgreiche
Anwendung des Parser sep liegt;
Rückgabe ist die Liste der Ergebnisse der Anwendungen
von p
...
D. Rösner FP 2013 . . .
24
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser: Kombinatoren
sepby p sep . . .
sepby :: Parser a -> Parser b -> Parser [a]
p ‘sepby‘ sep = (p ‘sepby1‘ sep) +++ return []
sepby1 :: Parser a -> Parser b -> Parser [a]
p ‘sepby1‘ sep = do a <- p
as <- many (do {sep; p})
return (a:as)
D. Rösner FP 2013 . . .
25
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser: Kombinatoren
chainl p op a . . . kombiniert Parser p und Parser op;
dabei liefern Anwendungen von op Funktionen,
die Resultate in linksassoziativer Weise bilden aus den
Ergebnissen von p vor und nach der Anwendung von op ;
a ist der Rückgabewert, falls Parser fehlschlägt
...
D. Rösner FP 2013 . . .
26
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser: Kombinatoren
chainl p op a . . .
chainl :: Parser a -> Parser (a -> a -> a) -> a -> Parser a
chainl p op a
= (p ‘chainl1‘ op) +++ return a
chainl1 :: Parser a -> Parser (a -> a -> a) -> Parser a
p ‘chainl1‘ op = do {a <- p; rest a}
where
rest a = do {f <- op; b <- p; rest (f a b)}
+++ return a
D. Rösner FP 2013 . . .
27
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser: Beispiele
Parser für klein- bzw. grossgeschriebene Zeichen, für
Buchstaben bzw. alphanumerische Zeichen
lower,upper
:: Parser Char
lower = sat isLower
upper = sat isUpper
letter
:: Parser Char
letter = sat isAlpha
alphanum
:: Parser Char
alphanum = sat isAlphaNum
D. Rösner FP 2013 . . .
28
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser: Beispiele
Kombinatoren für die Behandlung von Leerraum
space :: Parser String
space = many (sat isSpace)
token :: Parser a -> Parser a
token p = do {a <- p; space; return a}
apply :: Parser a -> String -> [(a,String)]
apply p = parse (do {space; p})
D. Rösner FP 2013 . . .
29
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Monadische Parser: Beispiele
Anwendung von ‘chainl1‘: akzeptiere Folge von Ziffern
und erzeuge den Wert der zugehörigen Integer-Zahl
natural :: Parser Int
natural = digit ‘chainl1‘ return (\m n -> 10*m + n)
nat :: Parser Int
nat = token natural
D. Rösner FP 2013 . . .
30
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Literatur: I
Paul Hudak.
The Haskell School of Expression – Learning Functional
Programming through Multimedia.
Cambridge University Press, Cambridge, UK, 2000.
ISBN 0-521-64338-4.
Simon Thompson.
Haskell - The Craft of Functional Programming.
Addison Wesley Longman Ltd., Essex, 1999.
2nd edition, ISBN 0-201-34275-8; Accompanying Web site:
http://www.cs.ukc.ac.uk/people/staff/sjt/craft2e.
D. Rösner FP 2013 . . .
31
Herunterladen