Funktionale Programmierung

Werbung
Parser in Haskell
Parser in Haskell
Gliederung
Funktionale Programmierung
Parser
1
D. Rösner
Institut für Wissens- und Sprachverarbeitung
Fakultät für Informatik
Otto-von-Guericke Universität Magdeburg
Parser in Haskell
. . . als Funktionen
. . . als Monaden
c
Sommer 2013, 6. Juni 2013, 2011-13
D.Rösner
D. Rösner FP 2013 . . .
Parser in Haskell
1
. . . als Funktionen
. . . als Monaden
Parser in Haskell
Eine Bibliothek von Bausteinen für Parser
2
. . . 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’
Grundidee (vgl. [Thompson 17.5]):
Parser als Funktionen
>token :: Eq a => a -> Parse a a
>token t (x:xs)
> | t==x
= [(t,xs)]
> | otherwise = []
>token t [] = []
Kombinatoren für Parser als Funktionen höherer Ordnung
Polymorphismus
D. Rösner FP 2013 . . .
D. Rösner FP 2013 . . .
4
D. Rösner FP 2013 . . .
5
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Parser in Haskell
Eine Bibliothek von Bausteinen für Parser
Eine Bibliothek von Bausteinen für Parser
die beiden elementaren Parser none bzw. succeed sind
Sonderfälle, die beide nichts konsumieren
spot . . . Verallgemeinerung von token; ein Parser, der ein
erstes Element in der Eingabeliste mit einer speziellen
Eigenschaft ’konsumiert’
none . . . schlägt dabei immer fehl
>none :: Parse a b
>none inp = []
>spot :: (a -> Bool) -> Parse a a
>spot p (x:xs)
> | p x
= [(x,xs)]
> | otherwise = []
>spot p [] = []
D. Rösner FP 2013 . . .
Parser in Haskell
. . . als Funktionen
. . . als Monaden
succeed . . . ist immer erfolgreich mit einem als Parameter
übergebenen Rückgabewert
>succeed :: b -> Parse a b
>succeed val inp = [(val,inp)]
6
D. Rösner FP 2013 . . .
. . . als Funktionen
. . . als Monaden
Parser in Haskell
Bibliothek für Parser: Kombinatoren
7
. . . 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 >*>:
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
>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 . . .
8
D. Rösner FP 2013 . . .
9
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Parser in Haskell
Bibliothek für Parser: Kombinatoren
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
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
. . . als Funktionen
. . . als Monaden
>list :: Parse a b -> Parse a [b]
>list p = (succeed [])
>
‘alt‘
>
((p >*> list p) ‘build‘ (uncurry (:)))
:: Parse a b -> (b -> c) -> Parse a c
>build p f inp = [(f x,rem)|(x,rem) <- p inp]
auch der Spezialfall einer leeren Liste ist zugelassen.
Diese wird vom Parser (succeed []) verarbeitet.
D. Rösner FP 2013 . . .
Parser in Haskell
10
D. Rösner FP 2013 . . .
. . . als Funktionen
. . . als Monaden
Parser in Haskell
Monadische Parser
11
. . . als Funktionen
. . . als Monaden
Monadische Parser
Quelle:
A HASKELL LIBRARY OF MONADIC PARSER COMBINATORS
der Typ:
newtype Parser a = Parser (String -> [(a,String)])
17th April 1997
die Monade:
Graham Hutton
University of Nottingham
Erik Meijer
University of Utrecht
instance Monad Parser where
return a = Parser (\cs -> [(a,cs)])
definiert wird eine Sammlung monadischer Kombinatoren
für Parser
p >>= f
= Parser (\cs -> concat [parse (f a) cs’ |
(a,cs’) <- parse p cs])
genutzt für zeichenweise arbeitende Parser
Verallgemeinerung möglich
D. Rösner FP 2013 . . .
13
D. Rösner FP 2013 . . .
14
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Parser in Haskell
Monadische Parser
. . . als Funktionen
. . . als Monaden
Monadische Parser
zusätzlich Parser als Instanz von MonadPlus:
der zugehörige Dekonstruktor
instance MonadPlus Parser where
mzero
= Parser (\cs -> [])
p ‘mplus‘ q = Parser (\cs -> parse p cs ++ parse q cs)
parse :: Parser a -> String -> [(a,String)]
parse (Parser p) = p
mzero . . . Parser, der immer fehlschlägt
‘mplus‘ . . . vereinige die Ergebnisse alternativer Parser
D. Rösner FP 2013 . . .
Parser in Haskell
15
. . . als Funktionen
. . . als Monaden
D. Rösner FP 2013 . . .
Parser in Haskell
Monadische Parser
16
. . . als Funktionen
. . . als Monaden
Monadische Parser
item . . . akzeptiert das erste Zeichen eines nichtleeren
String
sat . . . akzeptiert das erste Zeichen eines nichtleeren
String, wenn dieses einer Bedingung p genügt
item :: Parser Char
sat :: (Char -> Bool) -> Parser Char
item = Parser (\cs -> case cs of
""
-> []
(c:cs) -> [(c,cs)])
sat p = do c <- item
if p c then return c else mzero
D. Rösner FP 2013 . . .
17
D. Rösner FP 2013 . . .
18
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Parser in Haskell
Monadische Parser: Beispiele
Monadische Parser
string . . . nimmt einen String und liefert einen Parser, der
genau diesen akzeptiert
char c . . . akzeptiert genau das Zeichen c
char :: Char -> Parser Char
char c = sat (c ==)
string :: String -> Parser String
digit . . . akzeptiert eine Ziffer und gibt ihren Wert als
Integer zurück
string "" = return ""
digit :: Parser Int
digit = do {c <- sat isDigit;
return (ord c - ord ’0’)}
D. Rösner FP 2013 . . .
Parser in Haskell
. . . als Funktionen
. . . als Monaden
string (c:cs)
= do {char c; string cs; return (c:cs)}
19
D. Rösner FP 2013 . . .
. . . als Funktionen
. . . als Monaden
Parser in Haskell
Monadische Parser: Kombinatoren
20
. . . 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
force . . .
force :: Parser a -> Parser a
(+++)
:: Parser a -> Parser a -> Parser a
force p =
Parser (\cs -> let xs = parse p cs in
(fst (head xs), snd (head xs)) : tail xs)
p +++ q = Parser (\cs -> case parse (p ‘mplus‘ q) cs of
[]
-> []
(x:xs) -> [x])
D. Rösner FP 2013 . . .
21
D. Rösner FP 2013 . . .
22
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Parser in Haskell
Monadische Parser: Kombinatoren
Monadische Parser: Kombinatoren
many p . . . Parser, der null oder mehrere erfolgreiche
Anwendungen des Parsers p akzeptiert; zurückgegeben
wird der längste erfolgreiche Match
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
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 . . .
Parser in Haskell
. . . als Funktionen
. . . als Monaden
...
23
D. Rösner FP 2013 . . .
. . . als Funktionen
. . . als Monaden
Parser in Haskell
Monadische Parser: Kombinatoren
24
. . . als Funktionen
. . . als Monaden
Monadische Parser: Kombinatoren
sepby p sep . . .
chainl p op a . . . kombiniert Parser p und Parser op;
sepby :: Parser a -> Parser b -> Parser [a]
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
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
D. Rösner FP 2013 . . .
26
Parser in Haskell
. . . als Funktionen
. . . als Monaden
Parser in Haskell
Monadische Parser: Kombinatoren
. . . als Funktionen
. . . als Monaden
Monadische Parser: Beispiele
Parser für klein- bzw. grossgeschriebene Zeichen, für
Buchstaben bzw. alphanumerische Zeichen
chainl p op a . . .
lower,upper
:: Parser Char
chainl :: Parser a -> Parser (a -> a -> a) -> a -> Parser a
chainl p op a
lower = sat isLower
upper = sat isUpper
= (p ‘chainl1‘ op) +++ return a
chainl1 :: Parser a -> Parser (a -> a -> a) -> Parser a
letter
:: Parser Char
letter = sat isAlpha
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 . . .
Parser in Haskell
alphanum
:: Parser Char
alphanum = sat isAlphaNum
27
. . . als Funktionen
. . . als Monaden
D. Rösner FP 2013 . . .
Parser in Haskell
Monadische Parser: Beispiele
28
. . . als Funktionen
. . . als Monaden
Monadische Parser: Beispiele
Kombinatoren für die Behandlung von Leerraum
Anwendung von ‘chainl1‘: akzeptiere Folge von Ziffern
und erzeuge den Wert der zugehörigen Integer-Zahl
space :: Parser String
space = many (sat isSpace)
natural :: Parser Int
natural = digit ‘chainl1‘ return (\m n -> 10*m + n)
token :: Parser a -> Parser a
token p = do {a <- p; space; return a}
nat :: Parser Int
nat = token natural
apply :: Parser a -> String -> [(a,String)]
apply p = parse (do {space; p})
D. Rösner FP 2013 . . .
29
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