4

私の使用はText.Parsec少し錆びています。一致した文字列を返したいだけなら、これはイディオムですか?

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

liftM concat . many1無視しているorの既存の演算子があるように感じますが、(:) <$> 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

noneOf

あなたは私があなたが使っalphaNumた場所を使ったことに気付くでしょうnoneOf "/\n"。私noneOfは良い習慣ではないと思います。パーサーは、正しいことを受け入れるように本当に注意する必要があります。パーサーに受け入れてもらいたいと絶対に確信しています/qwerty/12345/!"£$%^&*()@:?><.,#{}[] \/ "/" /-=_+~か?それは本当に満足すべき/usr\local\binですか?

現状では、パーサーは、で始まり、そうでないもので/終わる限り、任意の文字列を受け入れます。を使用する代わりに、または同様のもので書き直す必要があると思います。を使用すると、何を許可する必要があるかを考えるのを避け、ポジティブな例だけを解析するのではなく、ポジティブな例を解析することに集中できます。\n/alphaNum <|> oneOf "_-.',~+"noneOfnoneOf

パーサー

私もいつものParser a代わりに行きましたStream s m t => ParsecT s u m a。それはただの怠惰なタイピングですが、私のコードが何をしているかを明確にするためにそれをしたふりをしましょう。:)もちろん、あなたに合った型の署名を使用してください。

于 2012-12-02T23:39:59.250 に答える