LoginSignup
5
4

More than 5 years have passed since last update.

haskell parsec個人メモ

Last updated at Posted at 2017-12-12

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

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

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4