我正在尝试编写一个执行简单if块代码的评估器。目前,我唯一感兴趣的两个条件是输入块的条件为true或false或条件为关系表达式。
前一种模式很好用,对我来说,实施它很有意义。
evalCond (Bool cond) = if cond then True else False
我认为我的病情是我的HenryVal
布尔值之一,然后在检查后返回正确的布尔值。
关于关系表达式评估,我不确定它出了什么问题。算术表达式由<x op y>
(不带空格)给出,并返回正确的二进制表达式数据。例如,<5<10>
将返回RBinary Less (Integer 5) (Integer 10)
。因此,当我转到每个不同表达式的评估函数时,条件会传递到它自己的函数中,该函数会将其评估为True或False。我当时认为此条件是String,因为它是将其传递给条件评估函数的唯一方法。如果我要传递RBinary op x y
,那么我会出错,因为RBinary需要三个参数,而不是一个。
此外,我知道该评估有效,因为在ghci中,如果我输入以下内容,则会得到正确的评估:
cond = "4 Less 5"
(henryBool2Bool (evalRBinOp (int2HenryInt (str2Int ((words cond) !! 0))) (evalROp ((words cond) !! 1)) (int2HenryInt (str2Int ((words cond) !! 2))) ))
通过命令行参数,如果输入以下内容,则会出现错误:
./hask "if <5<10>then x:=5 else x:=10"
hask: hask.hs:(336,1)-(338,137): Non-exhaustive patterns in function evalCond
因此,我认为也许将字符串转换为RBinary表达式的函数会更好,因为如果将它作为字符串传递,那么我可以将字符串评估为RBinary表达式,但这给了我同样的非穷尽模式错误。
下面是我的代码,其中包括我的数据类型和评估函数。
data HenryVal = Atom String
| String String
| Integer Integer
| Bool Bool
| Not HenryVal
| Neg HenryVal
| List [HenryVal]
| Seq [HenryVal]
| Assign String HenryVal
| If HenryVal HenryVal HenryVal
| While HenryVal HenryVal
| Skip
| ABinOp ABinOp
| RBinOp RBinOp
| ABinary ABinOp HenryVal HenryVal
| BBinary BBinOp HenryVal HenryVal
| RBinary RBinOp HenryVal HenryVal
data BBinOp = And | Or deriving (Show)
data RBinOp = Greater
| GEqual
| Less
| LEqual
deriving (Show)
data ABinOp = Add
| Subtract
| Multiply
| Divide
deriving (Show)
evalRBinOp :: HenryVal -> RBinOp -> HenryVal -> HenryVal
evalRBinOp (Integer a) Greater (Integer b) = Bool (a > b)
evalRBinOp (Integer a) Less (Integer b) = Bool (a < b)
evalRBinOp (Integer a) GEqual (Integer b) = Bool (a >= b)
evalRBinOp (Integer a) LEqual (Integer b) = Bool (a <= b)
evalCond :: HenryVal -> Bool
evalCond (Bool cond) = if cond then True else False
evalCond (String cond) = if (henryBool2Bool (eval (str2rbinary cond))) then True else False
--evalCond (String cond) = if (henryBool2Bool (evalRBinOp (int2HenryInt (str2Int ((words cond) !! 0))) (evalROp ((words cond) !! 1)) (int2HenryInt (str2Int ((words cond) !! 2))) )) == True then True else False
henryVal2Rop :: HenryVal -> RBinOp
henryVal2Rop (RBinOp Less) = Less
henryVal2Rop (RBinOp Greater) = Greater
str2Int :: String -> Integer
str2Int str = read (str) :: Integer
int2HenryInt :: Integer -> HenryVal
int2HenryInt num = Integer num
henryBool2Bool :: HenryVal -> Bool
henryBool2Bool (Bool True) = True
henryBool2Bool (Bool False) = False
henryBool2Bool (String "True") = True
henryBool2Bool (String "False") = False
str2rbinary :: String -> HenryVal
str2rbinary string = RBinary (evalROp ((words string) !! 1)) (int2HenryInt (str2Int ((words string) !! 0))) (int2HenryInt (str2Int ((words string) !! 2)))
evalROp :: String -> RBinOp
evalROp "Less" = Less
evalROp "Greater" = Greater
evalROp "GEqual" = GEqual
evalROp "LEqual" = LEqual
eval :: HenryVal -> HenryVal
eval val@(Atom _) = val
eval val@(String _) = val
eval val@(Integer _) = val
eval val@(Bool _) = val
eval val@(Neg _) = val
eval val@(Not _) = val
eval (List [Atom "quote", val]) = val
eval val@(List _) = val
eval val@(Seq _) = val
eval (If cond a b) = if (evalCond cond) then (eval a) else (eval b)
eval (While cond a) = a
eval (Assign var val) = val
eval val@(ABinOp _) = val
eval val@(RBinOp _) = val
eval (Skip) = Skip
eval (ABinary op x y) = evalABinOp (eval x) op (eval y)
eval (BBinary op x y) = evalBBinOp (eval x) op (eval y)
eval (RBinary op x y) = evalRBinOp (eval x) op (eval y)
所以我的问题是不知道如何评估RBinary
,因为它需要三个参数,但我们只给了一个参数cond
。我在GHCI中玩耍,发现如果将cond
而不是eval
传递给evalCond
,则可以将其视为三参数表达式。这样可以正确评估,并且有一个额外的好处,我可以删除evalCond
,但是如果以后需要的话我会保留它。解决该问题的代码是:
henryBool2Bool :: HenryVal -> Bool
henryBool2Bool (Bool True) = True
henryBool2Bool (Bool False) = False
henryBool2Bool (String "True") = True
henryBool2Bool (String "False") = False
eval (If cond a b) = if (henryBool2Bool (eval cond)) then (eval a) else (eval b)