Parsec --- 2.2 Sequence and choice

パーサをつなげてみようというお話.Parserはモナドだからdo記法でつなげることができます.

openClose:: Parser Char
openClose = do char '('
               char ')'

これで () だけをパースするパーサになるわけですか.

*Main> parseTest openClose "()"
')'
*Main> parseTest parens "("
parse error at (line 1, column 2):
unexpected end of input
expecting "(" or ")"

たしかに () を与えたときには「最後の )」を出力してますし,おかしな入力ではエラーを返してますね.すこしいじってみます.

openClose2:: Parser ()
openClose2 = do char '(' >> char ')'
                return ()

モナドなので,クラスメソッド(でいいのかな)>> で連結させて,閉じパーレンだけを返すのも何なので何も返さないようにしてみました.結果,

*Main> parseTest openClose2 "()"
()
*Main> parseTest openClose "("
parse error at (line 1, column 2):
unexpected end of input
expecting ")"

うまくいきました.なるほど.

パーサをつなげる(連接)のほかにも「選択」があります.入れ子のパーレンは

parens::Parser ()
parens = do char '(' >> parens >> char ')' 
            parens
         <|> -- これが「選択」
         return ()

とかけるようです.Parsecのドキュメントの記法は少し見にくいので書きかえています.(,入れ子のパーレン,),入れ子のパーレンとすることで,入れ子のパーレンそのものを再帰的に定義してます.パーレンの組以外のものがきたら,何も返さずに戻っています.

*Main> parseTest parens "(()())()"
()
*Main> parseTest parens "((()"
parse error at (line 1, column 5):
unexpected end of input
expecting "(" or ")"
*Main> parseTest parens "()))"
()

あれ?でも何で最後のOKなんでしょう?

あー・・・全部,パースしきってるわけではないということですか.(と)をパースしたあとに,)がきてるから,return ()に処理がうつってそれで終わりということですね.