Parsec 入門


Parsec コンビネータ count

count n p

count n p パーサコンビネータは第1引数に Int 値をとり、第2引数にパーサをとり、パターン p の n 回の繰り返しのパターンにマッチして、その値をリストにして返すパーサを返す。ちょっとややこしいが、実験してみる。
Prelude Text.Parsec> foo = (count 2 (string "bar")) :: Parsec String ()
 [String]

Prelude Text.Parsec> parseTest foo "barbarbarbar" ["bar","bar"]

上の実験は、count コンビネータが戻り値としてパーサを返すことを強調したかったのだが、動作の理解のためには次の例のほうが分かりやすいだろう。

Prelude Text.Parsec> parseTest (count 2 (string "buz")) "buzbuzbuz"
["buz","buz"]

myCount

この count パーサも簡単な Haskell のプログラムで定義されている。次の myCount がそのプログラムだ。

Prelude Text.Parsec> myCount n p | n <= 0 = return [] | otherwise =
 sequence (replicate n p)

myCount は count と同じように使える。

Prelude Text.Parsec> parseTest (myCount 2 (string "buz")) "buzbuzbuz"
["buz","buz"]

sequence

上のプログラムで sequence はモナドのリストを引数にとり、順次実行する関数だ。

Prelude Text.Parsec> sequence [(putStrLn "foo"), (putStrLn "bar"),
 (putStrLn "buz")]
foo
bar
buz
[(),(),()]

replicate

また replicate n p は要素 p を n 個含むリストを作る。

Prelude Text.Parsec> replicate 3 "foo"
["foo","foo","foo"]

したがって sequence (replicate n p) はパーサ p を n 回マッチさせるという意味になる。

Parsec のコンビネータは実際は Haskell のスニペットなので Hackage でソースを見るとその意味が分かることが多い。