Text.Parsec.Char モジュールには Parsec の基本的な(主に1文字の)パーサが記述されているが、驚いたことに string パーサ以外は全て satisfy コンビネータを用いて定義されている。例えば letter パーサの定義は次のようになる。 letter :: (Stream s m Char) => ParsecT s u m Char letter = satisfy isAlpha <?> "letter" satisfy コンビネータ自体もこのモジュールで定義されており、定義は次のようになっている。これには、Text.Parsec.Prim モジュールの tokenPrim コンビネータを利用している。 satisfy :: (Stream s m Char) => (Char -> Bool) -> ParsecT s u m Char satisfy f = tokenPrim (\c -> show [c]) ................................(\pos c _cs -> updatePosChar pos c) ................................(\c -> if f c then Just c else Nothing) tokenPrim の引数は全て関数で、第1引数はトークンの表示のための関数、第2引数はソース位置の計算、第3引数はパターンマッチのためのテスト関数である。1文字のパーサを作るための基本関数だが、satisfy を定義した後は1文字のパーサは全て satisfy 関数で定義できる。 唯一の例外は文字列のパターンマッチを行う string パーサで Text.Parsec.Char モジュールの定義では次のようになっている。Text.Parsec.Prim モジュールの tokens 関数を利用している。また show は文字列変換のための関数 updatePosString はパーサがマッチして消費が起きたときのソース位置 source position を計算するための関数である。updataPosString 関数は Text.Parsec.Pos モジュールで定義されている。 string :: (Stream s m Char) => String -> ParsecT s u m String string s = tokens show updatePosString s Text.Parsec.Prim モジュールの tokens 関数の定義は次のようになっている。 tokens showTokens nextposs tts@(tok:toks) ....= ParsecT $ \(State input pos u) cok cerr _eok eerr -> ....let ........errEof = (setErrorMessage (Expect (showTokens tts)) ..................(newErrorMessage (SysUnExpect "") pos)) ........errExpect x = (setErrorMessage (Expect (showTokens tts)) ...................... (newErrorMessage (SysUnExpect (showTokens [x])) pos)) ........walk [].... rs = ok rs ........walk (t:ts) rs = do ..........sr <- uncons rs ..........case sr of ............Nothing................ -> cerr $ errEof ............Just (x,xs) | t == x....-> walk ts xs ........................| otherwise -> cerr $ errExpect x ........ok rs = let pos' = nextposs pos tts ....................s' = State rs pos' u ................in cok tts s' (newErrorUnknown pos') ....in do ........sr <- uncons input ........case sr of ............Nothing........ -> eerr $ errEof ............Just (x,xs) ................| tok == x..-> walk toks xs ................| otherwise -> eerr $ errExpect x tokens はパーサを定義するための関数なので ParsecT $ \s cok cerr eok eerr -> funciton body で ParsecT モナドを作る。モナドのフィールドの関数の本体は in 以下で定義されている。let 句のヘルパー関数の定義を省略すると tokens で作成されるパーサは次のようになる。 ParsecT $\s cok cerr eok eerr -> ....in do ........sr <- uncons input ........case sr of ............Nothing........ -> eerr $ errEof ............Just (x,xs) ................| tok == x..-> walk toks xs ................| otherwise -> eerr $ errExpect x 冒頭で input 文字列から1文字を取り出す。つぎに、取り出した文字 sr について case 分岐し、さらに Just (x,xs) 以下のガードの分岐の3分岐している。 case 分岐の Nothing は input 文字列が空の場合でエラー終了 eerr $ errEof する。Just (x, xs) のときは input 文字列から1文字 x と残りの文字列 xs が取り出される。tok は let のヘルパー関数で取り出されたトークンの文字列の先頭の文字だ。 x の値によってガードで分岐するが tok == x のときはヘルパー関数の walk 関数で残りの文字列のマッチを繰り返す。otherwise では異常終了なのでエラー処理をする。 let 句のヘルパー関数についても簡単に眺めてみる。 errEof, errExpect x はエラー情報 ParseError を定義している。 ........errEof = (setErrorMessage (Expect (showTokens tts)) ..................(newErrorMessage (SysUnExpect "") pos)) ........errExpect x = (setErrorMessage (Expect (showTokens tts)) ...................... (newErrorMessage (SysUnExpect (showTokens [x])) pos)) walk (t:ts) rs 関数はパーサの文字列 (t:ts) と input 文字列 rs のマッチングを行う関数だ。再帰的に文字列の先頭の文字を比較する作業を繰り返している。 .......walk [].... rs = ok rs ........walk (t:ts) rs = do ..........sr <- uncons rs ..........case sr of ............Nothing................ -> cerr $ errEof ............Just (x,xs) | t == x....-> walk ts xs ........................| otherwise -> cerr $ errExpect x ok 関数はパターンマッチが成功したときの処理をする関数である。関数内でパーサ位置とパーサ状態を変更している。 ........ok rs = let pos' = nextposs pos tts ....................s' = State rs pos' u ................in cok tts s' (newErrorUnknown pos') コードを読んだ限りでは token 関数は汎用と言うよりは string パーサを生成するための専用関数のように見える。
by tnomura9
| 2019-08-12 09:00
| Haskell
|
Comments(0)
|
カテゴリ
新型コロナウイルス 主インデックス Haskell 記事リスト 圏論記事リスト 考えるということのリスト 考えるということ ラッセルのパラドックス Haskell Prelude Ocaml ボーカロイド 圏論 jQuery デモ HTML Python ツールボックス XAMPP Ruby ubuntu WordPress 脳の話 話のネタ リンク 幸福論 キリスト教 心の話 メモ 電子カルテ Dojo JavaScript C# NetWalker ed と sed HTML Raspberry Pi C 言語 命題論理 以前の記事
最新のトラックバック
最新のコメント
ファン
記事ランキング
ブログジャンル
画像一覧
|
ファン申請 |
||