Haskell
Parser
個人メモ
parsec
個人的なメモ

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 ")"
"-------------------"

この記事はどんどん追記していきます!!