0

Parsecパッケージを使用してHaskellでパーサーを作成しようとしています。入力のルールの一部では、パーサーがルールのオプションと一致する必要があります。ルールのうち、複数のルールが一致する可能性がありますが、少なくとも1つのルールが一致する必要があります。一致しない場合、パーサーはエラーを生成することが予想されます。

例を挙げましょう。とという名前の2つのParsecルールがあると仮定firstmoreます。次の可能性があります。

  • 入力が一致し、その後に;firstが続きます。more
  • 入力は一致するだけfirstです; またはその
  • 入力はにのみ一致しmoreます。

firstいずれの場合も、またはの少なくとも1つがmore一致する必要があります。これを行う方法についてのアイデアはありますか?使用することを考えました<|>が、正しく理解していれば、ルールの1つ(つまり、最初に成功したルール)にしか一致しませ

編集:

明確化:とが両方とも一致する場合はfirstmore両方の結果を返す必要があります。一方だけが一致する場合、もう一方の戻り値は、のようなnull値になる可能性がありますが、との両方をNothing返すことはできません。Nothingfirstmore

4

3 に答える 3

4

物事が来るはずだと仮定することは、いくつかの特定の順序です:

atLeastOne :: [Parser a] -> Parser [a]
atLeastOne ps = do
  rs <- catMaybes <$> mapM optionMaybe ps
  if null rs
    then parserFail "At least one thing should be present"
    else return rs
于 2013-01-21T12:43:32.150 に答える
1

本当に単純な方法は次のとおりです。

oneOrBoth first_ more_ = try both <|> first <|> more where
    first = (:[]) <$> first_
    more  = (:[]) <$> more_
    both  = liftM2 (++) first more

これにより、長さ 1 または 2 のリストが生成されますが、可能であれば長さ 2 のリストを生成することが優先されます。

于 2013-01-21T16:39:37.667 に答える
0

他の回答ほど一般的ではありませんが、これで問題は解決します。

atLeastOne :: ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m (Maybe a, Maybe b)
atLeastOne p1 p2 = firstMatches <|> secondMatches <|> fail "Invalid input"
    where
        firstMatches = do
            a <- p1
            maybeB <- (p2 >>= Just <|> return Nothing)
            return (Just a, maybeB)
        secondMatches = do
            b <- p2
            return (Nothing, Just b)

使用法:

atLeastOne first more

後で編集:

または、よりタイプセーフなバージョン:

data Choice3 a b c = Choice1Of3 a | Choice2Of3 b | Choice3Of3 c

atLeastOne :: ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m (Choice1Of3 a b (a, b))
atLeastOne p1 p2 = firstMatches <|> secondMatches <|> fail "Invalid input"
    where
        firstMatches = do
            a <- p1
            (p2 >>= \b -> Choice3Of3 (a, b)) <|> Choice1Of3 a
        secondMatches = do
            b <- p2
            return $ Choice2Of3 b
于 2013-01-21T12:51:59.833 に答える