Parsec 入門


Parsec anyToken

anyToken

anyToken はどんなトークンもマッチする。しかし、トークンが空のときだけエラーを返す。トークンというのがよくわからないが、文字の場合もトークンとして反応するようだ。
Prelude Text.Parsec> parseTest anyToken "abc"
'a'
Prelude Text.Parsec> parseTest anyToken "\n"
'\n'
Prelude Text.Parsec> parseTest anyToken ""
parse error at (line 1, column 1):

多バイト文字にも反応する。

Prelude Text.Parsec> parseTest anyToken "あいうえお"
'\12354'

notFollowedBy

notFollowedBy パーサと組み合わせると eof パーサを作ることができる。

Prelude Text.Parsec> parseTest (notFollowedBy anyToken) ""
()
Prelude Text.Parsec> parseTest (notFollowedBy anyToken) "abc"
parse error at (line 1, column 1):
unexpected 'a'

Prelude Text.Parsec> parseTest eof "" () Prelude Text.Parsec> parseTest eof "abc" parse error at (line 1, column 1): unexpected 'a' expecting end of input

トークンとは何か

トークンとは何なのかが気になったので anyToken の型を調べてみた。

Prelude Text.Parsec> :t anyToken
anyToken :: (Show t, Stream s m t) => ParsecT s u m t

この中で Stream というクラスが気になったので調べてみた。

Prelude Text.Parsec> :i Stream
class Monad m => Stream s (m :: * -> *) t | s -> t where
uncons :: s -> m (Maybe (t, s))
{-# MINIMAL uncons #-}
-- Defined in ‘Text.Parsec.Prim’
instance [safe] Monad m => Stream [tok] m tok
-- Defined in ‘Text.Parsec.Prim’

Stream クラスの uncons という関数があるようだ。

Prelude Text.Parsec> uncons "foo"
Just ('f',"oo")

引数の先頭の文字と、残りの文字列のペアを作る関数のようだ。

結局トークンの意味は分からなかった。Parsec はまだ謎が多い。とにかく anyToken パーサは文字列が空ではないことに反応することがわかった。