首页 > 解决方案 > Haskell:为什么在执行数据评估时不执行我的算术评估函数?

问题描述

我正在编写一种简单的语言,但遇到了一个问题,即算术表达式并不期望它们的运算符,尽管它们是在语言中定义的。从那以后我回去更简单地表达我的程序。目前,我唯一的复杂表达式是算术。我可以解析整数、字符串、布尔值和列表。它可以识别诸如“5 Add 5”之类的表达式,但只能以列表的形式“[5 Add 5]”。

由于原子的解析方式,我怀疑当它不在列表中时它不会解析。原子解析器解析布尔值,然后解析任意原子。如果将算术表达式放入字符串中,它也将被正确解析。

我不确定为什么它没有正确评估。我有一个处理算术表达式的评估函数,但是当我尝试通过命令行为其提供参数时它不起作用。当我将它加载到 GHCI 中时,我可以完美地使用它,所以我知道算术评估函数有效,但是当我给它命令行参数时,我看不出它为什么不评估。任何算术表达式只会导致表达式本身,而不是应该返回的值。

我能想到的唯一原因是,当解析表达式时,它不会被解析为算术表达式,而是被解析为列表或字符串。

data HenryVal = Integer Integer
              | Bool Bool
              | Atom String
              | String String 
              | List [HenryVal]
              | ABinOp ABinOp
              | Ad HenryVal HenryVal
              | ABinary ABinOp HenryVal HenryVal

data ABinOp = Add
            | Subtract
            | Multiply
            | Divide
             deriving (Show)

evalABinOp :: HenryVal -> ABinOp -> HenryVal -> HenryVal
evalABinOp (Integer a) Add (Integer b) = Integer (a +b)
evalABinOp (Integer a) Multiply (Integer b) = Integer (a * b)
evalABinOp (Integer a) Divide (Integer b) = Integer (a `div` b)
evalABinOp (Integer a) Subtract (Integer b) = Integer (a - b) 

eval :: HenryVal -> HenryVal
eval val@(Atom _) = val
eval val@(String _) = val
eval val@(Integer _) = val
eval val@(Bool _) = val
eval (List [Atom "quote", val]) = val
eval val@(List _) = val
eval (ABinary op x y) = evalABinOp (eval x) op (eval y)

spaces :: Parser ()
spaces = skipMany1 space

parseString :: Parser HenryVal
parseString = do
    char '"'
    x <- many (noneOf "\"")
    char '"'
    return $ String x

parseList :: Parser HenryVal
parseList = liftM List $ sepBy parseExpr spaces

parseNumber :: Parser HenryVal
parseNumber = liftM (Integer . read) $ many1 digit

parseAtom :: Parser HenryVal
parseAtom = do 
              first <- letter
              rest <- many (letter <|> digit)
              let atom = first:rest
              return $ case atom of 
                         "True" -> Bool True
                         "False" -> Bool False
                         _ -> Atom atom

parseExpr :: Parser HenryVal   
parseExpr =  parseNumber <|>
             parseAtom   <|>
             parseString <|>
             do
                 _ <- char '['
                 x <- try parseList
                 _ <- char ']'
                 return x

readExpr :: String -> HenryVal
readExpr input = case parse parseExpr "Henry" input of
    Left error -> String $ "No Match: " ++ show error
    Right val -> val

main :: IO ()
main = getArgs >>= print . eval . readExpr . head

标签: parsinghaskellcompiler-construction

解决方案


推荐阅读