如何在Haskell上创建一个简单的计算器?

时间:2017-11-20 22:45:11

标签: haskell

我想实现一个读取字符串并对其执行数学运算的程序。

addop, mulop :: Parser (Expr -> Expr -> Expr)
addop = (infixOp "+" Add) <|> (infixOp "-" Sub)
mulop = infixOp "*" Mul

int :: Parser Expr
int = do
  n <- number
  return (Lit n)

expr :: Parser Expr
expr = term `chainl1` addop

term :: Parser Expr
term = factor `chainl1` mulop

factor :: Parser Expr
factor = int <|> parens expr

run :: String -> Expr
run = runParser expr

eval :: Expr -> Int
eval ex = case ex of
   Add a b -> eval a + eval b
   Mul a b -> eval a * eval b
   Sub a b -> eval a - eval b
   Lit n   -> n

evExpr :: String -> Maybe Integer
evExpr [] = Nothing
evExpr str = Just (eval (run str))

但我有错误:

• Couldn't match type ‘Int’ with ‘Integer’

  Expected type: Maybe Integer
    Actual type: Maybe Int
• In the expression: Just (eval (run str))
  In an equation for ‘evExpr’: evExpr str = Just (eval (run str))
   |
37 | evExpr str = Just (eval (run str))
   |              ^^^^^^^^^^^^^^^^^^^^^

 • Couldn't match type ‘SourceName
                       -> [Char] -> Either ParseError Expr’
                 with ‘Expr’
  Expected type: String -> Expr
    Actual type: () -> SourceName -> [Char] -> Either ParseError Expr
• Probable cause: ‘runParser’ is applied to too few arguments
  In the expression: runParser expr
  In an equation for ‘run’: run = runParser expr
   |
26 | run = runParser expr
   |       ^^^^^^^^^^^^^^

当程序正常运行时,我应该看到这样:

•evExpr“27-(6 * 3 + 5%2)”=只是8

请帮帮我。谢谢

1 个答案:

答案 0 :(得分:5)

函数eval会返回Int,但在evExpr中,您试图将Int推送到Maybe Integer(基于类型签名) evExpr)。 Int不是Integer,因此您会收到错误消息。您可以更改eval以返回Integer,更改evExpr以返回Maybe Int,或将Int转换为Integer { {1}}。

发生第二个错误,因为fromIntegral具有类型签名:

runParser

但是您使用runParser :: GenParser tok st a -> st -> SourceName -> [tok] -> Either ParseError a Parser Expr来调用它,并遗漏了StringSourceName个参数。

我猜你的解析器没有任何用户状态,所以你可以使用:

st

哪个不需要用户状态(因为它具有类型parse :: Stream s Identity t => Parsec s () a -> SourceName -> s -> Either ParseError a ),但仍需要您传递源的名称。类似的东西:

()

您遇到的下一个问题是run :: String -> Either ParseError Expr run = parse expr "<string>" 如果解析器遇到解析错误,则无法返回run。解析器返回Expr,您必须在Either ParserError Expr中处理该问题。实际上,检查evExpr中的空列表/ String没有意义,因为解析器将处理它(并生成错误)。您最好更改evExpr以返回evExpr,并Either ParseError Int fmap超过解析器结果。

eval