2013-08-18 21 views
5

Próbuję nauczyć Parsec i próbuję parsować prosty adres e-mail. Próbowałem następujący kod. Mój oczekiwany wynik to cały adres e-mail jako ciąg. Ale kiedy uruchomię kod, otrzymam tylko ".com". Czy mógłbyś powiedzieć mi, co się dzieje?Haskell Parsec woes

{-# LANGUAGE NoMonomorphismRestriction #-} 

import Text.Parsec 
import Control.Applicative hiding ((<|>)) 

email = many1 alphaNum 
    *> char '@' 
    *> many1 alphaNum 
    *> string ".com" 

emailstr = parse email "" "[email protected]" 

Odpowiedz

12

Podpis typ dla *> mówi, że zwraca wynik z drugim parsera i wyrzuca wynik z pierwszej parsera. Tak więc email zwraca tylko wynik ostatniego parsera w sekwencji.

Co prawdopodobnie chcesz coś bardziej jak

email = 
    stitch 
    <$> many1 alphaNum 
    <*> char '@' 
    <*> many1 alphaNum 
    <*> string ".com" 

ten biegnie cztery parser i przekazuje wynik każdego jako argument stitch. Jeśli piszesz odpowiednią implementację stitch:

stitch a b c d = a ++ [b] ++ C++ d 

następnie należy wrócić swój ciąg.

Zauważ, że w tym momencie, można również umieścić nazwę użytkownika i domenę do oddzielnych pól struktury danych czy coś:

data Email = Email {username, domain :: String} 

email = 
    Email 
    <$> many1 alphaNum 
    <* char '@' 
    <*> ((++) <$> many1 alphaNum <*> string ".com") 

Teraz twój parser zwraca strukturę Email raczej niż tylko zwykłym sznurkiem. To może nie być to, czego szukasz, ale pokazuje, jak napisać bardziej wyrafinowany analizator składni.

Wszystko to używa interfejsu Applicative do Parsetu, który jest ogólnie uważany za dobry styl. inne sposobem korzystania parsec jest interfejs Monad:

email = do 
    a <- many1 alphaNum 
    b <- char '@' 
    c <- many1 alphaNum 
    d <- string ".com" 
    return (a ++ [b] ++ C++ d) 
+0

Czy to idiomatyczne drogą do osiągnięcia powiedział zadanie? Nie będę używać kodu w produkcji gdziekolwiek. Po prostu próbuję nauczyć się parsetu. – Jay

+0

Oba sposoby są idiomatyczne – nponeccop