2012-03-01 6 views
2

プロジェクト用の単純なテキストテンプレート言語用のパーサーを作成しています。uu-parsinglibのコンビネータopt(重要な場合はバージョン2.7.3.2)を完全に塞いでいます。どのように正しく使用するためのアイデアですか?uu-parsinglibで `opt`コンビネータを使用しています

ここに私の苦境を示す非常に単純化された例があります。

{-# LANGUAGE FlexibleContexts #-} 

import Text.ParserCombinators.UU hiding (pEnd) 
import Text.ParserCombinators.UU.Utils 
import Text.ParserCombinators.UU.BasicInstances 

pIdentifier :: Parser String 
pIdentifier = pMany pLetter 

pIfClause :: Parser ((String, String), String, Maybe (String, String), String) 
pIfClause = (,,,) <$> pIf <*> pIdentifier <*> pOptionalElse <*> pEnd 

pIf :: Parser (String, String) 
pIf = pBraces ((,) <$> pToken "if " <*> pIdentifier) 

pOptionalElse :: Parser (Maybe (String, String)) 
pOptionalElse = (((\x y -> Just (x, y)) <$> pElse <*> pIdentifier) `opt` Nothing) 

pElse :: Parser String 
pElse = pBraces (pToken "else") 

pEnd :: Parser String 
pEnd = pBraces (pToken "end") 

main :: IO() 
main = do 
    putStrLn $ show $ runParser "works" pIfClause "{if abc}def{else}ghi{end}" 
    putStrLn $ show $ runParser "doesn't work" pIfClause "{if abc}def{end}" 

最初の文字列を正しく解析しますが、2番目はエラーで失敗します。optため

main: Failed parsing 'doesn't work' : 
Expected at position LineColPos 0 12 12 expecting one of [Whitespace, "else"] at LineColPos 0 12 12 : 
           v 
        {if abc}def{end} 
          ^

答えて

2

ドキュメントは言う:

If p can be recognized, the return value of p is used. Otherwise, the value v is used. Note that opt by default is greedy.

<<|>のドキュメントに説明されてい貪欲何の手段:

<<|> is the greedy version of <|>. If its left hand side parser can make any progress then it commits to that alternative.

elseendの両方がeで始まるので、optの最初の引数は入力の一部を認識します。したがって、それはpElseにコミットし、失敗すると解析が失敗します。

ドキュメントを参考にして、... <|> pure Nothingを使用すると簡単に解決できます。

+0

ありがとう、私はそれを試みたと思ったが、明らかにそうではなかった。 "<|> pure Nothing"が動作します。 –

関連する問題