Haskell : 函数中的非穷尽模式阻止另一个函数执行,即使它没有被使用

Haskell : Non-Exhaustive Pattern In Function Prevents Another Function From Executing Even Though Its Not Used

我正在尝试将 car, cdr, and cons 功能实现到我正在编写的玩具语言中,但是当我尝试通过 main 执行我的 car 功能时,出现以下错误:

./parser "car [1 2 3]"
parser: parser.hs:(48,27)-(55,45): Non-exhaustive patterns in case

第 48-55 行的函数如下:

parseOp :: Parser HVal
parseOp = (many1 letter <|> string "+" <|> string "-" <|> string "*" <|> string "/" <|> string "%" <|> string "&&" <|> string "||") >>= 
      (\x -> return $ case x of
                "&&" -> Op And
                "||" -> Op Or
                "+" -> Op Add
                "-" -> Op Sub
                "*" -> Op Mult
                "/" -> Op Div
                "%" -> Op Mod)

我真的不确定为什么错误消息指向这个函数,因为它与列表功能无关。然而 car 函数正在运行,因为我能够通过 GHCI 成功执行它。我知道我的问题是由于解析引起的,但我看不到它在哪里。以下是与列表相关的函数。我从他们身上看不出他们是如何受到parseOp.

影响的
data HVal = Number Integer
          | String String
          | Boolean Bool
          | List [HVal]
          | Op Op
          | Expr Op HVal HVal
          | Car [HVal]
           deriving (Read)

car :: [HVal] -> HVal
car xs = head xs


parseListFunctions :: Parser HVal
parseListFunctions = do
            _ <- string "car "
            _ <- char '['
            x <- parseList
            _ <- char ']'
            return $ Car [x]
            

parseExpr :: Parser HVal
parseExpr =  parseNumber
         <|> parseOp
         <|> parseBool
     <|> parseListFunctions 
         <|> do
        _ <- char '['
                x <- parseList
                _ <- char ']'
                return x
         <|> do
            _ <- char '('
            x <- parseExpression
                _ <- char ')'
                return x

eval :: HVal -> HVal
eval val@(Number _) = val
eval val@(String _) = val
eval val@(Boolean _) = val
eval val@(List _) = val -- Look at list eval NOT WORKING
eval val@(Op _) = val
eval (Expr op x y) = eval $ evalExpr (eval x) op (eval y)
eval (Car xs) = eval $ car xs

parseOp中删除many1 letter将相同的错误传递给以下函数parseBool

parseBool :: Parser HVal
parseBool = many1 letter >>= (\x -> return $ case x of
                                               "True" -> Boolean True
                                               "False" -> Boolean False)

你写

parseExpr = ... <|> parseOp <|> ... <|> parseListFunctions <|> ...

等等

car ...

先传给parseOp,然后parseListFunctionsparseOp 解析器在

中成功
many1 letter

分支,所以在\x -> return $ case x of ...x绑定到"car"。因为 parseOp 成功(并且 returns 一个带有嵌入的错误值,not-yet-evaluated 不穷尽的大小写错误!),parseListFunctions 从未尝试过。

您将需要修改语法以减少其中的歧义,这样就不会出现多个分支可能匹配的冲突。