4

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

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

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

4

2 回答 2

4

没关系,我想。稍微明智的命名会使其更漂亮:

category = concat <$> many1 segment
  where
    segment = (:) <$> char '/' <*> many1 (noneOf "/\n")
于 2012-12-02T19:14:45.643 回答
3

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

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

我认为没有像您想知​​道的那样的组合器,但这是 Haskell,并且 roll-your-own-control-structure-or-combinator 始终可用:

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

没有

You'll notice I've used alphaNum where you used noneOf "/\n". I think noneOf is not good practice; parsers should be really careful to accept onlt the right thing. Are you absolutely sure you want your parser to accept /qwerty/12345/!"£$%^&*()@:?><.,#{}[] \/ "/" /-=_+~? Should it really be happy with /usr\local\bin?

As it stands, your parser accepts any string as long as it starts with / and ends before \n with something that's not /. I think you should rewrite it with alphaNum <|> oneOf "_-.',~+" or similar instead of using noneOf. Using noneOf allows you to avoid thinking about what you should allow and focus on getting positive examples to parse instead of only positive examples to parse.

Parser

I've also always gone for Parser a instead of Stream s m t => ParsecT s u m a. That's just lazy typing, but let's pretend I did it to make it clearer what my code was doing, shall we? :) Use what type signature suits you, of course.

于 2012-12-02T23:39:59.250 回答