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.LanguagePrelude 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 として読み飛ばしてくれる。