2013-08-18 144 views
5

我想學習Parsec,並試圖解析一個簡單的電子郵件地址。 我試過下面的代碼。我的預期輸出是整個電子郵件地址作爲一個字符串。但是當我運行這些代碼時,我只能得到「.com」。有人可以告訴我發生了什麼事嗎?Haskell Parsec困境

{-# LANGUAGE NoMonomorphismRestriction #-} 

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

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

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

回答

12

*>類型簽名說,它返回從解析器的結果,並拋出遠離第一解析器的結果。因此,email只返回序列中最終解析器的結果。

你可能需要的是更多的東西一樣

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

這將運行四個解析器並將每個結果作爲參數傳遞給stitch。如果你寫stitch一個合適的實現:

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

那麼你應當得到您的字符串。

注意,在這一點上,你也可以把用戶名和域到數據結構或某事的不同的領域:

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

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

現在解析器返回Email結構,而不是隻是一個簡單的字符串。這可能不是你想要的,但它演示瞭如何編寫更復雜的解析器。

所有這些都是使用Parsec的Applicative接口,這通常被認爲是很好的風格。使用秒差距的其他方式是Monad接口:

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

這是慣用的方式來完成任務的說?我不會在任何地方使用生產中的代碼。我只是試圖學習parsec。 – Jay

+0

這兩種方式都是慣用的 – nponeccop