0

より完全な問題のために編集されました:

以前のパーサーの結果を取得し、結果に特定のコンストラクターが含まれている場合に条件付きで失敗するパーサー (私は uu​​-parsinglib を使用しています) を作成したいと思います。

これはモナドパーサーでなければならないことに気づきました。

非直接左再帰を含む文法があります。以下に問題を示しますが、現実はもう少し複雑です。

data Field = 
       Field_A  A
       Field_B  B
       Field_C  C
       Field_D  String

data A =
       A Prefix String

data B =
       B Prefix String

data C =
       C Prefix String

data Prefix = 
       Prefix Field

ほとんどの場合、私はフィールドのみに関心があり、後戻りを最小限に抑えるために、そのケースに焦点を当てるのが最善です。

役立つ演算子を定義しました

(<..>) :: IsParser p => p (a -> b) -> p (b -> c) -> p (a -> c)
g <..> f = (.) <$> f <*> g

そして、私は次のように問題に取り組みます。

pField :: Parser Field 
pField =  
   ( Field_D <$> pString ) <??>
   pChainl' ( pReturn (helper) <*> pPrefix' ) ( pA' <<|> pB' <<|> pC' )
   where pChainl' :: IsParser p =>  p (f -> (pre -> f) -> f) -> 
                                       p (pre -> f) -> 
                                       p (f -> f)
         pChainl' op x = must_be_non_empties "pChainl'" op x (
                            flip f <$> pList1 (flip <$> op <*> x)
                         )
         f x [] = x
         f x (func:rest) = f (func x) rest
         helper :: (Field -> Prefix) -> 
                      Field -> 
                      (Prefix -> Field) -> 
                      Field
         helper p i n = n $ p i

左の関連付けを維持しながら、初期フィールドを渡すことができる pChainl のバリアントを定義したことに注意してください。

pA' :: Parser (Prefix -> Field)
pA' = ( (flip A) <$> pString ) <..> pReturn Field_A

pB' :: Parser (Prefix -> Field)
pB' = ( (flip B) <$> pString ) <..> pReturn Field_B

pC' :: Parser (Prefix -> Field)
pC' = ( (flip C) <$> pString ) <..> pReturn Field_C

-- This consumes no input
pPrefix' :: Parser (Field -> Prefix)
pPrefix' = pReturn Prefix

私が定義したい質問

pA :: Parser A

pField に関しては、右端の Field コンストラクターが Field_A でない場合にポスト フィルターが失敗します。正しく指摘されているように、これはモナド解析です。uu-parsinglib をモナド パーサーとして使用する説得力のある例を見つけることができないので、提案されたアプローチは何でしょうか?

間違ったツリーを吠えている場合は、それもお知らせください。

4

2 に答える 2

1

パーサーによって返された値が何らかのテストに合格した場合にのみ成功する、一般化された条件付きパーサーを作成できるようです。もちろん、これはモナド機能を使用します。ただし、これが uu-parsinglib で良いことかどうかはわかりません。私のテストでは問題なく動作しているように見えますが、例外が 1 つあります。条件が失敗し、入力を消費するためのパーサーが他にない場合、ライブラリは例外をスローします。(修正手順が指定されていないという線に沿ったもの...)

pConditional :: Parser a -> (a -> Bool) -> Parser a
pConditional p test = p >>= (\result -> case (test result) of
    True -> pure result
    False -> empty)

また、そのような条件付きパーサーを自由に使用することから生じる他の落とし穴についても知りたいです。(もしあれば。)

于 2013-12-04T07:01:44.763 に答える