【问题标题】:Haskell: Non-exhaustive patterns error arises on pattern that I have accounted for alreadyHaskell:我已经解释过的模式会出现非详尽模式错误
【发布时间】:2020-08-30 04:00:03
【问题描述】:

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

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

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

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

当涉及到关系表达式求值时,我不太确定哪里出了问题。算术表达式由<x op y>(不带空格)给出,并返回正确的二进制表达式数据。例如<5<10> 将返回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)

【问题讨论】:

  • 您的 evalCond 函数明确地仅适用于字符串或布尔文字,但不适用于关系表达式。您正在将表达式RBinary Less (Integer 5) (Integer 10) 传递给evalCond,它没有RBinary 的模式。
  • 令我困惑的是RBinaryevalCond 中的表示会导致错误,因为RBinary 在evalRBinOp 中的声明和评估都需要三个参数。我不确定如何继续。
  • 我不确定我理解你的意思。您对evalCond 中的RBinary 进行了哪些尝试,它给出了什么错误?
  • @user2407038 我试图用evalCond (RBinary cond) = ... 之类的函数更简单地思考这个函数的问题是它需要三个参数,但我只提供了一个参数。
  • @user2407038 这就是为什么我想将其视为一个字符串,然后将其转换为一个 RBinary 表达式,然后可以对其进行评估,但这是行不通的。关于参数数量问题,我回到eval 并包括以下eval (If cond a b) = if (evalRBinOp (cond!!0) (cond!!1) (cond!!2)) then (eval a) else (eval b)。这给了我以下错误:Couldn't match expected type ‘[HenryVal]’ with actual type ‘HenryVal’ .

标签: haskell eval evaluation expression-evaluation


【解决方案1】:

所以我的问题是不知道如何评估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)

【讨论】:

  • (Bool True)(Bool False) 的案例可以折叠为 henryBool2Bool (Bool bool) = bool
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多