这是文字使用Text.Parsec吗?

时间:2012-12-02 14:44:34

标签: haskell parsec

我对Text.Parsec的使用有点生疏。如果我只想返回匹配的字符串,这是惯用的吗?

category :: Stream s m Char => ParsecT s u m [Char]                        
category = concat <$> (many1 $ (:) <$> char '/' <*> (many1 $ noneOf "/\n"))

我觉得我可能忽略了liftM concat . many1(:) <$> p1 <*> p2的现有运营商,但我不确定。

2 个答案:

答案 0 :(得分:4)

我认为没关系。一点点明智的命名会让它变得更漂亮:

category = concat <$> many1 segment
  where
    segment = (:) <$> char '/' <*> many1 (noneOf "/\n")

答案 1 :(得分:3)

我认为稍微更多惯用Parsec来返回更结构化的东西,例如字符串列表:

catList :: Parser [String]    
catList = char '/' *> many1 alphaNum `sepBy1` char '/'

我认为没有像你想知道的那样的组合器,但这是Haskell,并且你自己的控制结构或组合器总是可用的:

concatMany1 :: Parser [a] -> Parser [a]
concatMany1 p = concat <$> many1 p

catConcat = concatMany1 $ (:) <$> char '/' <*> many1 alphaNum

但是这个下一个组合器甚至更好,至少是惯用的Haskell:

infixr 5 <:>
(<:>) :: Applicative f => f a -> f [a] -> f [a]
hd <:> tl = (:) <$> hd <*> tl

现在我们可以写

catCons :: Parser String
catCons = concatMany1 (char '/' <:> many1 alphaNum)

但顺便说一句

contrivedExample :: IO String
contrivedExample = getChar <:> getLine

moreContrived :: String -> Maybe String
moreContrived name = find isLetter name <:> lookup name symbolTable

noneOf

您会注意到我使用了alphaNum noneOf "/\n"。我认为noneOf不是好的做法;解析器应该非常小心地接受正确的事情。您是否确定要让解析器接受/qwerty/12345/!"£$%^&*()@:?><.,#{}[] \/ "/" /-=_+~?它真的应该对/usr\local\bin感到满意吗?

就目前而言,只要解析器以/开头,并且在\n之前以/为结尾,您的解析器就会接受任何字符串。我认为您应该使用alphaNum <|> oneOf "_-.',~+"或类似内容重写它,而不是使用noneOf。使用noneOf可以避免考虑应该允许什么,并专注于获取解析的正面示例,而不是仅解析 正面示例。

分析器

我也总是去Parser a而不是Stream s m t => ParsecT s u m a。这只是懒惰的打字,但让我假装我这样做是为了让我的代码更清楚,我们呢? :)当然,使用什么类型的签名适合你。