2013-08-18 55 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