haskell parsec個人メモ
parsecのドキュメント
http://jakewheat.github.io/intro_to_parsing/#_first_parser
を参考にメモをしていく。
使うにはbuild-dependsにparsecを追加する。
モジュールはたくさんあるが、とりあえず
#パーサの実行
パーサの実行にはparse関数を使う。
引数は
parse <パーサ> <名前> <パースしたい文字列>
みたいにして渡す。
<名前>は単に識別としてつかうので別に"hoge"とかでもいい。
parsecのドキュメントどおり、パースの実行を簡易にするためのrunという関数を
定義すると便利だろう。
import Text.Parsec.Char
import Text.Parsec.Prim
import Text.Parsec.String
--パーサの簡易実行と出力をする関数
run::Show a => Parser a -> String -> IO ()
run p input =
case parse p "hoge" input of
Left err ->
putStr "parse error at" >> print err
Right x -> print x
Text.Parsec.Char
文字のパーサが定義されている。
oneOf
任意の文字列kを設定し、パース対象の文字列から一文字受け取り、文字列kのどれか一文字に一致したらパースを成功させる
run (oneOf "abc") "aaa" -- 'a'がパースされる
run (oneOf "abc") "bac" -- 'b'がパースされる
run (oneOf "abc") "zabc" -- パース失敗
noneOf
任意の文字列kを設定し、パース対象の文字列から一文字受け取り、文字列kのどの文字にも一致しなければパースを成功させる
run (noneOf "abc") "aaa" -- パース失敗
run (noneOf "abc") "bac" -- パース失敗
run (noneOf "abc") "zabc" -- 'z'がパースされる
Text.Parsec.Prim
パーサの実行など、パーサの基本的な操作が定義されている。
Text.Parsec.String
String型をパースするパーサの型Parserが型シノニムとして定義されている。
Text.Parsec.Combinator
コンビネータを定義している。
eof
文字列の終端が来たらパースを成功させる
run (char 'a') "abc" --"a"がパースされる
run (char 'a' >> eof) "abc" --パース失敗。文字列が残っている!
charパーサ
--"()"をパースする
openClose :: Parser String
openClose =do
a <- char '('
b <- char ')'
return [a,b]
main :: IO ()
main = do
run openClose "()"
print "-----------"
run openClose "(4)"
print "-----------"
run openClose "(("
print "-----------"
run openClose "()44444"
実行結果
"()"
"-----------"
parse error at"hoge" (line 1, column 2):
unexpected "4"
expecting ")"
"-----------"
parse error at"hoge" (line 1, column 2):
unexpected "("
expecting ")"
"-----------"
"()"
むむむ、最後の結果には注意だ。
()44444がパースに成功している。
どうやら余った文字があったとしても成功判定になるらしい。
<|>コンビネータ
<|>コンビネータを使うと「または」を表現することができる。
例えばaまたはbまたはcにマッチするパーサはこう。
a_b_c ::Parser Char
a_b_c = char 'a' <|> char 'b' <|> char 'c'
main :: IO ()
main = do
run a_b_c "a"
run a_b_c "b"
run a_b_c "c"
run a_b_c "d"
実行結果
'a'
"-------------------"
'b'
"-------------------"
'c'
"-------------------"
parse error at"hoge" (line 1, column 1):
unexpected "d"
expecting "a", "b" or "c"
"-------------------"
パーサの再帰
パーサは、自分自身を再帰的に呼び出すことができる。
parens :: Parser String
parens = do
a <- char '('
c <- parens
b <- char ')'
return $ a:c++[b]
<|>
return []
main :: IO ()
main = do
run parens "()"
run parens "(())"
run parens "((()))"
run parens ")"
run parens "(("
実行結果
"()"
"-------------------"
"(())"
"-------------------"
"((()))"
"-------------------"
""
"-------------------"
parse error at"hoge" (line 1, column 3):
unexpected end of input
expecting "(" or ")"
"-------------------"