Haskell:我已经考虑过的模式出现了非穷举模式错误

问题描述 投票:-2回答:1

我正在尝试编写一个执行简单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)
haskell eval evaluation expression-evaluation language
1个回答
0
投票

所以我的问题是不知道如何评估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)
© www.soinside.com 2019 - 2024. All rights reserved.