使用Haskell编写一个简单的解释器来执行数学表达式
发布时间:2023-12-10 03:28:55
以下是使用Haskell编写的一个简单的解释器,用于执行数学表达式。
module Main where
import Text.Parsec
import Text.Parsec.String
-- 表达式的数据类型
data Expr = Lit Int | Add Expr Expr | Sub Expr Expr | Mul Expr Expr | Div Expr Expr
-- 解析器,用于将字符串解析为表达式
exprParser :: Parser Expr
exprParser = chainl1 term addOp
term :: Parser Expr
term = chainl1 factor mulOp
factor :: Parser Expr
factor = parens exprParser <|> number
addOp :: Parser (Expr -> Expr -> Expr)
addOp = (do{ char '+'; return Add }) <|> (do{ char '-'; return Sub })
mulOp :: Parser (Expr -> Expr -> Expr)
mulOp = (do{ char '*'; return Mul }) <|> (do{ char '/'; return Div })
parens :: Parser a -> Parser a
parens p = do{ char '('; x <- p; char ')'; return x }
number :: Parser Expr
number = fmap (Lit . read) $ many1 digit
-- 计算表达式的值
eval :: Expr -> Int
eval (Lit n) = n
eval (Add e1 e2) = eval e1 + eval e2
eval (Sub e1 e2) = eval e1 - eval e2
eval (Mul e1 e2) = eval e1 * eval e2
eval (Div e1 e2) = eval e1 div eval e2
main :: IO ()
main = do
putStrLn "Enter a mathematical expression (e.g., 2 + 3 * (4 - 1)): "
input <- getLine
case parse exprParser "" input of
Left err -> putStrLn $ "Error: " ++ show err
Right expr -> putStrLn $ "Result: " ++ show (eval expr)
上述代码中,Expr 数据类型用于表示数学表达式,它可以是一个整数字面量 (Lit Int),或者是两个表达式的运算结果 (Add, Sub, Mul 和 Div)。
解析器部分使用 Parsec 库来将输入字符串解析为 Expr 类型的表达式。exprParser 是最顶层的解析器,它将多个项 (terms) 通过加法或减法操作符链在一起。term 解析一个项,它将多个因子 (factors) 通过乘法或除法操作符链在一起。factor 解析一个因子,它要么是一个括号内的表达式,要么是一个整数字面量。
在 eval 函数中,我们使用模式匹配来计算表达式的值。如果表达式是一个整数字面量,则返回该整数。如果是加法、减法、乘法或除法运算符的表达式,则递归地计算每个操作数的值,然后进行相应的运算。
main 函数是程序的入口。它首先提示用户输入一个数学表达式,然后使用解析器将输入的字符串解析为 Expr 类型的表达式。如果解析成功,则计算表达式的值并打印出来;如果解析失败,则打印错误消息。
下面是一个使用例子:
Enter a mathematical expression (e.g., 2 + 3 * (4 - 1)): 2 + 3 * (4 - 1) Result: 11
在这个例子中,输入的表达式是 2 + 3 * (4 - 1),解析成功后计算得到结果 11。
