如何在Haskell中使用Parsec隐式乘法解析表达式

时间:2016-10-07 21:01:11

标签: parsing haskell parsec

我有一个允许隐式乘法的语法,(1+2)(3+4)(1+2)*(3+4)相同或(1+2)7(1+2)*7相同 我如何在Haskell中实现它?以下是我到目前为止的情况:

import Control.Monad
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Expr
import Text.ParserCombinators.Parsec.Language
import qualified Text.ParserCombinators.Parsec.Token as Token

languageDef =
  emptyDef { Token.identStart      = letter
           , Token.identLetter     = alphaNum
           , Token.reservedOpNames = ["+", "*"]
           }

lexer = Token.makeTokenParser languageDef

reservedOp = Token.reservedOp lexer
parens     = Token.parens     lexer
integer    = Token.integer    lexer

data Expr = Const Int
          | Binary BinOp Expr Expr
            deriving (Show)

data BinOp = Add | Multiply
             deriving (Show)

expression = buildExpressionParser operators term

operators = [ [Infix  (reservedOp "*"   >> return (Binary Multiply)) AssocLeft]
            , [Infix  (reservedOp "+"   >> return (Binary Add     )) AssocLeft]
            ]

term =   liftM (Const . fromIntegral) integer
     <|> parens expression
     <|> (do e1 <- expression
             e2 <- term
             return $ Binary Multiply e1 e2)

parseString str =
  case parse expression "" str of
    Left e  -> error $ show e
    Right r -> r

但它不起作用,我在解析时出错,当我尝试解析((1 + 5) 8)时我有unexpected "8" expecting operator or ")"

1 个答案:

答案 0 :(得分:1)

除非你有充分的理由支持makeTokenParser背后的机制,否则看起来有点矫枉过正。通常,当您的语言与现有语言非常相似,或者您有许多不同级别的运算符优先级时,这很有用。在您的情况下,您可以在几行中编写expression ...

import Text.Parsec.String (Parser) 
import Text.Parsec
import Control.Applicative (some)

-- ...

expression :: Parser Expr
expression = sum
  where
    product = foldl1 (Binary Multiply) <$> factor `sepBy1` optional (char '*')
    sum     = foldl1 (Binary Add)      <$> product `sepBy1` char '+'
    factor  = int <|> between (char '(') (char ')') expression
    int     = Const . read <$> some digit

 -- ...

然后,在GHCi:

ghci> parseString "1+2*3"
Binary Add (Const 1) (Binary Multiply (Const 2) (Const 3))
ghci> parseString "(1+2)(3+4)"
Binary Multiply (Binary Add (Const 1) (Const 2)) (Binary Add (Const 3) (Const 4))
ghci> parseString "(1+2)*(3+4)"
Binary Multiply (Binary Add (Const 1) (Const 2)) (Binary Add (Const 3) (Const 4))
ghci> parseString "(1+2)7"
Binary Multiply (Binary Add (Const 1) (Const 2)) (Const 7)
ghci> parseString "(1+2)*7"
Binary Multiply (Binary Add (Const 1) (Const 2)) (Const 7)