私はあなたがMonadError
間違った理由で関与しようとしているという印象を受けています。
でtry (many1 parser1) <|> parser2
、回避しようとしている動作は、との使用に起因しますtry
。<|>
それが気に入らない場合は、別のコンビネータを使用してください。おそらく、のような表現(many1 parser1) >> parser2
があなたにとってよりうまくいくでしょうか?(これにより、からの結果が破棄され(many1 parser1)
ます。もちろん、からの結果を使用して、からの結果と組み合わせることができます>>=
。)(many1 parser1)
parser2
(注:この点より下では、目前の問題に対する本当に良い解決策はありません。いくつかのことがおそらく機能しない理由についてのいくつかの考えがあります...うまくいけば、これは(ある程度)啓発的かもしれませんが、あまり期待しないでください多くの。)
ParsecT/MonadErrorの相互作用の詳細な調査。少し面倒だと思いますが、OPがやりたいことを実行するための最善の方法はまだよくわかりませんが、少なくとも、成功しなかった理由についての洞察が得られることを願っています。元のアプローチ。
まず、ParsecがMonadErrorのインスタンスであると言うのは正しくないことに注意してください。Parsecは、内側のモナドがIdentityの場合にParsecTによって生成されるモナドです。ParsecTは、それ自体が操作するMonadErrorのインスタンスである内部モナドが指定されている場合にのみ、MonadErrorのインスタンスを生成します。GHCi相互作用の関連フラグメント:
> :i Parsec
type Parsec s u = ParsecT s u Identity
-- Defined in Text.Parsec.Prim
-- no MonadError instance
instance (MonadError e m) => MonadError e (ParsecT s u m)
-- Defined in Text.Parsec.Prim
-- this explains why the above is the case
-- (a ParsecT-created monad will only become an instance of MonadError through
-- this instance, unless of course the user provides a custom declaration)
次に、catchErrorとParsecTを使用した実際の例を見てみましょう。このGHCiの相互作用を考えてみましょう。
> (runParserT (char 'a' >> throwError "some error") () "asdf" "a" :: Either String (Either ParseError Char)) `catchError` (\e -> Right . Right $ 'z')
Right (Right 'z')
タイプの注釈が必要なようです(これは私には直感的に理解できるようですが、元の質問には関係がないため、詳しく説明しません)。表現全体のタイプは、GHCによって次のように決定されます。
Either String (Either ParseError Char)
したがって、通常の解析結果が得られます---通常のモナドの代わりにモナドにEither ParseError Char
ラップされます。はのインスタンスなので、 /を使用できますが、渡されるハンドラーはもちろん正しいタイプの値を生成する必要があります。これは、構文解析ルーチンから抜け出すのにあまり役立ちません。恐れ入ります。Either String
Identity
Either String
MonadError
throwError
catchError
catchError
質問のサンプルコードに戻ります。それは少し違うことをします。ret
質問で定義されているタイプを調べてみましょう。
forall (m :: * -> *) a.
(Monad m) =>
m (Either [Char] (Either ParseError a))
(GHCiによると...{-# LANGUAGE NoMonomorphismRestriction #-}
型注釈なしでコードをコンパイルするには、で単相性の制限を解除する必要があったことに注意してください。)
そのタイプは、で面白いことをする可能性についてのヒントret
です。どうぞ:
> runParserT ret () "asdf" "a"
Right (Left "some error")
後から考えると、与えられたハンドラーはcatchError
を使用して値を生成するunexpected
ので、もちろんそれはパーサーになります...そして私はこれを打ち出すのに役立つ何かにこれを打ち込む方法がわかりません解析プロセス。