6

Parsec を使用すると、型の関数String -> Maybe MyTypeを比較的簡単に作成できます。Readそれに基づいて、自分のタイプのインスタンスを作成したいと思います。ただし、どのように機能するのか、何をするべきなのかわかりませreadsPrecん。

私の最善の推測でreadsPrecは、再帰パーサーをゼロから構築して文字列をトラバースし、Haskell で目的のデータ型を構築するために使用されます。しかし、私はすでに非常に堅牢なパーサーを持っており、まさにそれを実行してくれます。readsPrecでは、パーサーを使用するように指示するにはどうすればよいでしょうか? それが取る「演算子の優先順位」パラメータとは何ですか?私のコンテキストでは何に役立ちますか?

それが役立つ場合は、Github で最小限の例を作成しました。これには、型、パーサー、および空の Read インスタンスが含まれており、行き詰まった場所をよく反映しています。

(背景: 本当のパーサーは Scheme 用です。)

4

1 に答える 1

3

しかし、私はすでに非常に堅牢なパーサーを持っており、まさにそれを実行してくれます。

実際にはそれほど堅牢ではありません。パーサーには余分な括弧の問題があり、解析できません

((1) (2))

たとえば、一部の不正な入力に対して例外がスローされます。

singleP = Single . read <$> many digit

使用することがありますread "" :: Int

邪魔にならないように、優先順位引数は、括弧が必要かどうかを判断するために使用されます。

infixr 6 :+:

data a :+: b = a :+: b

data C = C Int

data D = D C

application の優先順位は の優先順位よりも高いため、C 12の引数としてa を括弧で囲む必要はありませんが、 の引数として括弧で囲む必要があります。(:+:)(:+:)C 12D

したがって、通常は次のようなものがあります

readsPrec p = needsParens (p >= precedenceLevel) someParser

wheresomeParserは括弧で囲まずに入力からの値をneedsParens True thing解析し、thing括弧の間をneedsParens False thing解析しますが、thing オプションで括弧で囲まれた a を解析します [常に必要以上の括弧を受け入れる必要があり、((((((1))))))としてうまく解析する必要がありIntます]。

パーサーは、リストやタプルなどを読み取るときに入力の一部を値の一部として解析するためreadsPrec pに使用されるため、解析された値だけでなく、入力の残りの部分も返さなければなりません。

parsecこれにより、パーサーをパーサーに変換する簡単な方法は次のようにreadsPrecなります。

withRemaining :: Parser a -> Parser (a, String)
withRemaining p = (,) <$> p <*> getInput

parsecToReadsPrec :: Parser a -> Int -> ReadS a
parsecToReadsPrec parsecParser prec input
    = case parse (withremaining $ needsParens (prec >= threshold) parsecParser) "" input of
        Left _ -> []
        Right result -> [result]

ただし、GHC を使用している場合は、パーサーの代わりにReadPrec / ReadP( を使用して構築された) パーサーを使用し、 の代わりに定義する方が望ましい場合があります。Text.ParserCombinators.ReadP[rec]parsecreadPrecreadsPrec

于 2013-01-25T15:06:28.943 に答える