Attoparsec の使い方を学ぶのは非常に難しいと思います。なぜなら、ドキュメントは実際には単なる API ドキュメントであり、基本的にチュートリアルがないからです (FPComplete のものを除く)。Attoparsec を学ぶことができる他の場所を知っていれば、それは素晴らしいことです。
次の形式で単純な分子名を解析する必要があります: NaCl
, CO2
, H2O
, . 要素名は、オプションで小文字が続く大文字です
(記号が 2 文字を超える要素は考慮していません)。
要素の後には数字を続けることができます(数式の添字になります)。HCN
H2O2
新しいバージョン (Mark と Tarmil の提案のおかげで) はコンパイルされますが、解析されません:
module Chem
where
import Data.Text (Text, pack)
import Control.Applicative ((<*>), (<$>))
import Data.Attoparsec.Text
data Element = Element String Int deriving (Eq, Ord, Show)
type Molecule = [Element]
parseString :: String -> Result Molecule
parseString = parse (many' parseElement) . pack
parseElement :: Parser Element
parseElement = do
el <- (++) <$> pClass "A-Z" <*> option "" (pClass "a-z")
n <- option 1 decimal
return $ Element el n
pClass :: String -> Parser String
pClass cls = (\c -> [c]) <$> satisfy (inClass cls)
どんな提案でも大歓迎です。
編集:私はそれを実行することができました。基本的に、Partial
継続が返されました。解析を完了するには、空のバイト文字列をパーサーに供給する必要があります。したがって、正しいのparseString
は次のとおりです。
parseString = flip feed empty . parse (many' parseElement) . pack
はどこempty
ですかData.Text.empty
。ただし、インクリメンタル解析は必要ないため、便利な関数 がありますparseOnly
。これは、追加の入力を待機せず、 を返しますEither
。
それを念頭に置いて、次のようにコードを書き直しました(現在は動作しています):
module Chem
where
import Data.Text (Text, pack)
import Control.Applicative ((<*>), (<$>))
import Data.Attoparsec.Text
data Element = Element String Int deriving (Eq, Ord, Show)
type Molecule = [Element]
parseString :: String -> Either String Molecule
parseString = parseOnly (many' parseElement) . pack
parseElement :: Parser Element
parseElement = do
el <- (++) <$> pClass "A-Z" <*> option "" (pClass "a-z")
n <- option 1 decimal
return $ Element el n
pClass :: String -> Parser String
pClass cls = (\c -> [c]) <$> satisfy (inClass cls)