Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
560 views
in Technique[技术] by (71.8m points)

haskell - Chaining unary operators with megaparsec

I have written a parser using megaparsec for a very simple language consisting of integer literals and two unary operators "a" and "b":

data ValueExpr = OpA ValueExpr  
               | OpB ValueExpr
               | Integer Integer

valueExpr :: Parser ValueExpr
valueExpr = makeExprParser valueTerm valueOperatorTable

valueTerm :: Parser ValueExpr
valueTerm = parenthesised valueExpr
          <|> Integer <$> integerLiteral

integerLiteral :: Parser Integer
integerLiteral = -- omitted

valueOperatorTable :: [[Operator Parser ValueExpr]]
valueOperatorTable = [[unaryOp "a" AOp,
                       unaryOp "b" BOp]]

parenthesised :: Parser a -> Parser a
parenthesised = between (char '(') (char ')')

unaryOp :: Text -> (a -> a) -> Operator Parser a
unaryOp name f = Prefix (f <$ symbol name)

binaryOp :: Text -> (a -> a -> a) -> Operator Parser a
binaryOp name f = InfixL (f <$ symbol name)

However, it seems that this doesn't allow me to "chain" unary operators, i.e. when trying to parse "ab1", I'm met with "unexpected 'b'". Why is that?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is briefly mentioned in the documentation for makeExprParser:

Unary operators of the same precedence can only occur once (i.e., --2 is not allowed if - is prefix negate). If you need to parse several prefix or postfix operators in a row, ... you can use this approach:

manyUnaryOp = foldr1 (.) <$> some singleUnaryOp

This is not done by default because in some cases allowing repeating prefix or postfix operators is not desirable.

In your specific example, something like the following ought to work:

valueOperatorTable :: [[Operator Parser ValueExpr]]
valueOperatorTable = [[Prefix unaryOps]]

unaryOps :: Parser (ValueExpr -> ValueExpr)
unaryOps = foldr1 (.) <$> some (OpA <$ symbol "a" <|> OpB <$ symbol "b")

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...