2013-01-21 42 views
0

我想使用Parsec包在Haskell中編寫解析器。輸入規則的一部分需要解析器匹配規則選項。在規則之外,多於一個規則可能匹配,但至少至少一個規則必須匹配,否則預計分析器會產生錯誤。如何在Parsec中形成一個OR選項,它可以匹配很多選項,但必須至少匹配一個選項?

讓我舉個例子。假設我們有兩個名爲firstmore的Parsec規則。有可能是:

  • 輸入匹配first後跟more;
  • 輸入只匹配first;或者
  • 輸入只匹配more

在任何情況下,至少有一個firstmore必須匹配。任何想法如何做到這一點?我想過使用<|>,但如果我理解正確,它只會匹配規則的一個(即第一個成功)。

編輯:

澄清:如果兩個firstmore比賽,必須同時返回的結果。如果只有一個匹配,另一個的返回值可以是一些空值,如Nothing,但不允許爲firstmore返回Nothing

+0

你的意思是說,相同的輸入可以被'first'和'more'解析,並且你想要返回兩個結果嗎? –

+0

@DanielFischer:是的,確切的。更新了問題。 – gablin

+0

我想再澄清一次。當你說「第一個和第二個匹配」時,你的意思是第一個>>更多的匹配,或者是從這個位置開始的第一個匹配,而從這個位置開始的更多匹配? –

回答

3

假設的東西應該而來的是一些特定的順序:

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 
+0

這似乎是這樣做的最習慣的方式。 =) – gablin

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) 

用法:

後編輯:

還是更類型安全的版本:

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 
1

的真的很幼稚的方法是這樣的:

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

這將產生長度爲一個或兩個的列表,以偏愛在可能的情況下產生長度爲2的列表。

相關問題