0

私はParsecで文字列を解析することを学び始めたばかりで、次の問題に直面しています。

次のコードには 3 つのパーサーの実行が含まれており、そのうちの 2 つは明らかに失敗します。奇妙なことに、カスタムの失敗メッセージは、3 回目ではなく 2 回目の実行でのみ発生します。

import Text.Parsec
import Text.Parsec.String

ps :: Parser String
ps = (string "123") <|> (string "456") <|> fail "my-failure"

main = do
     putStrLn $ "A: " ++ show (parse ps "" "123")
     putStrLn $ "\nB: " ++ show (parse ps "" "789")
     putStrLn $ "\nC: " ++ show (parse ps "" "45x")

出力:

A: Right "123"

B: Left (line 1, column 1):
unexpected "7"
expecting "123" or "456"
my-failure

C: Left (line 1, column 1):
unexpected "x"
expecting "456"

2番目の左側の部分が失敗したときに常に失敗メッセージを表示させる正しい方法は何<|>ですか? 以前に発生したエラーを上書きできますか?

4

1 に答える 1

9

Parsecの<|>コンビネータは、パーサーが入力を消費しない場合にのみ、次のオプションを試みます。あなたの場合、パーサーstring "456"は の先頭に一致する"45x"ため、それ以上の代替手段は試行されません。任意の先読みが必要な場合は、try関数を使用する必要があります。

ps :: Parser String
ps = string "123" <|> try (string "456") <|> fail "my-failure"

のParsecのドキュメントから<|>

このコンビネータは選択を実装します。パーサー p <|> q は最初に p を適用します。成功すると、p の値が返されます。p が入力を消費せずに失敗した場合、パーサー q が試行されます。このコンビネータは、MonadPlus クラスの mplus メンバーおよび Alternative の (<|>) メンバーと同等に定義されています。

パーサー p が入力を消費しなかった場合 (つまり、先読みが 1 の場合) にのみ q が試行されるため、パーサーは予測型と呼ばれます。この非バックトラッキング動作により、パーサー コンビネーターの効率的な実装と適切なエラー メッセージの生成の両方が可能になります。

于 2013-03-13T07:47:11.087 に答える