Haskell:非详尽模式错误出现在我已经解释过的模式上

Haskell: Non-exhaustive patterns error arises on pattern that I have accounted for already

我正在尝试编写一个执行简单 if 代码块的求值器。目前我唯一感兴趣的两个条件是进入块的条件是真还是假,或者条件是关系表达式。

前一种模式运行良好,对我来说在实现它时很有意义。

evalCond (Bool cond) = if cond then True else False

我认为我的条件是我的 HenryVal 布尔值之一,然后我 return 检查后的正确布尔值。

当涉及到关系表达式求值时,我不太确定哪里出错了。算术表达式由 <x op y>(没有空格)给出,return 是正确的二进制表达式数据。例如 <5<10> 会 return RBinary Less (Integer 5) (Integer 10)。因此,当我转到每个不同表达式的评估函数时,条件被传递到它自己的函数中,该函数将其评估为 True 或 False。我当时将此条件视为一个字符串,因为这是将其传递给条件评估函数的唯一方式。如果我要传递 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)