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 2015, 12. Juni 2015, 2011-15 D.Rösner D. Rösner FP 2015 . . . 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 2015 . . . D. Rösner FP 2015 . . . 4 D. Rösner FP 2015 . . . 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 2015 . . . 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 2015 . . . . . . 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 2015 . . . 8 D. Rösner FP 2015 . . . 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 2015 . . . Parser in Haskell 10 D. Rösner FP 2015 . . . . . . 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 2015 . . . 13 D. Rösner FP 2015 . . . 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 2015 . . . Parser in Haskell 15 . . . als Funktionen . . . als Monaden D. Rösner FP 2015 . . . 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 2015 . . . 17 D. Rösner FP 2015 . . . 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 2015 . . . Parser in Haskell . . . als Funktionen . . . als Monaden string (c:cs) = do {char c; string cs; return (c:cs)} 19 D. Rösner FP 2015 . . . . . . 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 2015 . . . 21 D. Rösner FP 2015 . . . 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 2015 . . . Parser in Haskell . . . als Funktionen . . . als Monaden ... D. Rösner FP 2015 . . . 23 . . . 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 2015 . . . 25 D. Rösner FP 2015 . . . 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 2015 . . . Parser in Haskell alphanum :: Parser Char alphanum = sat isAlphaNum 27 . . . als Funktionen . . . als Monaden D. Rösner FP 2015 . . . 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 2015 . . . 29 D. Rösner FP 2015 . . . 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 2015 . . . 31