Parsec 入門


Parsec makeTokenParser ユーザ設定

GenLanguageDef

makeTokenParser でトークンパーサを自動作成するときのユーザ設定は、GenLanguageDef を設定することでおこなう。それもスクラッチで作る必要はなく、myDef = emptyDef {commentStart = "/*", commentEnd = "*/" } のように、デフォールトのファイルを使って、フィールド名を指定して設定することができる。

なぜこのようなことができるのだろうか。

代数的データ型のフィールドラベル付きフィールド

デフォールトの設定レコードを再利用するテクニックは、代数的データ型のフィールドラベル付きフィールドを活用することで実行できる。

Haskell の フィールドラベルをもつ代数的データ型は、フィールドラベルを指定することでデータを取り出したり、変更したりすることができる。そこで、次のような簡単な代数的データ型を作って実験してみた。

Prelude> data Foo = Foo {foo :: String, bar :: String} deriving Show

Foo 型のデータは次のようにフィールドラベルなしでも、フィールドラベルを使っても作ることができる。

Prelude> Foo "hello" "world"
Foo {foo = "hello", bar = "world"}
Prelude> Foo {bar = "world", foo = "hello"}
Foo {foo = "hello", bar = "world"}

また、元あるデータの一部分を変更した新しいデータを作ることもできる。

Prelude> hello = Foo "hello" "world"
Prelude> hello
Foo {foo = "hello", bar = "world"}
Prelude> howdy = hello {foo = "howdy"}
Prelude> howdy
Foo {foo = "howdy", bar = "world"}

ユーザ設定のカスタムレコード

このようなフィールドラベル付きの代数的データ型を利用して、ユーザ設定のカスタムレコードを次のように作ることができる。

Prelude> import Text.Parsec
Prelude Text.Parsec> import Text.Parsec.Token
Prelude Text.Parsec Text.Parsec.Token> import Text.Parsec.Language

Prelude Text.Parsec Text.Parsec.Token Text.Parsec.Language> myDef = emptyDef {commentStart = "/*", commentEnd = "*/"} Prelude Text.Parsec Text.Parsec.Token Text.Parsec.Language> lexer = makeTokenParser myDef

Prelude Text.Parsec Text.Parsec.Token Text.Parsec.Language> parseTest (whiteSpace lexer >> string "hello") "/* any comment */ hello" "hello"

commentStart と commentEnd を設定するだけでコメント部分は whiteSpace として読み飛ばしてくれる。