より完全な問題のために編集されました:
以前のパーサーの結果を取得し、結果に特定のコンストラクターが含まれている場合に条件付きで失敗するパーサー (私は 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 をモナド パーサーとして使用する説得力のある例を見つけることができないので、提案されたアプローチは何でしょうか?
間違ったツリーを吠えている場合は、それもお知らせください。