尽管数据处理在别处处理,但功能错误中的非详尽模式

Non-exhaustive pattern in function error despite the data handling being handled elsewhere

我正在尝试编写一种简单的语言,目前我正在尝试实现一个循环,但每次我 运行 程序时,我都会收到一个错误,指出其中有一个非详尽的模式evalStatement_ 函数。

----- Main -----
readStatement :: String -> IO [HStatement]
readStatement input = do
        program <- readFile input
        case parse parseProgram "Olivia" program of
          Left err -> fail $ show err
          Right parsed -> return $ parsed


evalString :: Env -> String -> IO String
evalString env expr = do
        x <- readStatement expr
        concat <$> mapM (runIOThrows . liftM show . evalStatement_ env) x
        --mapM (runIOThrows . liftM show . evalStatement env) x

        -- evalStatement env x
        --map (\exprs -> runIOThrows $ liftM show $ evalStatement env exprs) x
        --map (runIOThrows $ liftM show $ evalStatement env) x
        --runIOThrows $ liftM show $ (evalStatement env x)   -- >>= runIOThrows $ liftM show $ evalStatement env

evalAndPrint :: Env -> String -> IO ()
evalAndPrint env expr = do
        evalString env expr
        return ()

run :: String -> IO ()
run expr = nullEnv >>= flip evalAndPrint expr

main :: IO ()
main = do
        args   <- getArgs
        run $ args !! 0

----- Error -----
Main: Expr.hs:(82,1)-(85,34): Non-exhaustive patterns in function evalStatement_
-----------------

evalStatement_ :: Env -> HStatement -> IOThrowsError ()
evalStatement_ env (Do cond expr) = evalDo env (Do cond expr)
evalStatement_ env (Print val) = do
         x <- evalVal env val
         liftIO $ putStrLn $ show x 

evalDo :: Env -> HStatement -> IOThrowsError ()
evalDo env (Do cond expr) = evalVal env cond >>= \x -> case x of
                                                           HBool False -> return ()
                                                           HBool True  -> do
                                                                   traverse_ (evalVal env) expr
                                                                   evalStatement_ env $ Do cond expr

evalVal :: Env -> HVal -> IOThrowsError HVal
evalVal env val @(HInteger _) = return $ val
evalVal env val @(HBool    _) = return $ val
evalVal env val @(HString  _) = return $ val
evalVal env val @(HList    _) = return $ val
evalVal env (Arith x op y)    = evalArithmetic env x op y
evalVal env (Assign var val)  = evalVal env val >>= defineVar env var

我将错误归结为这些函数。我使用 evalStatement_ 来计算 DoPrint 函数。我已经测试了 print 并且它确实有效,但我不明白为什么 evalDo 没有。 evalVal 按预期工作,所以我不知道非详尽问题所在的位置。我 运行 使用 -Wall -Wextra 的编译命令,它根据语句数据类型给了我以下内容。

Expr.hs:82:1: warning: [-Wincomplete-patterns]
    Pattern match(es) are non-exhaustive
    In an equation for ‘evalStatement_’:
        Patterns not matched:
            _ (Eval _)
            _ (Program _)
   |
82 | evalStatement_ env (Do cond expr) = evalDo env (Do cond expr)
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...

 data HStatement
   =  Eval   HVal
   |  Print  HVal
   |  Do     HVal [HVal]
   |  Program [HVal]
    deriving (Eq, Read)

我不确定为什么 EvalProgram 会对一些实际上没有使用它们的东西产生影响,或者我完全遗漏了什么?

您的 main 程序在从您的源文件解析的完整语句列表中按顺序 运行 evalStatement_ 显示:

evalString :: Env -> String -> IO String
evalString env expr = do
        x <- readStatement expr
        concat <$> mapM (runIOThrows . liftM show . evalStatement_ env) x 
                   ^^^^ runs on every statement in the list `x`

如果语句列表 x :: [HStatement] 包含任何 ProgramEval 语句,那么这将导致 运行 时间错误,因为仅 evalStatement_处理 DoPrint 构造函数。

因此,正如@jpmarinier 评论的那样,如果您希望在任何有效语句上调用 evalStatement_,那么您需要处理编译器在您打开 -Wall 时警告您的所有情况。

以下缺失案例的定义可能对您有用 运行ning:

evalStatement_ env (Program pgm) = mapM_ (evalStatement_ env) pgm
evalStatement_ env (Eval val) = do
    result <- evalVal env val
    return ()

请注意 Eval 的大小写非常无用。由于 evalStatement_ 不能 return 除了 () 以外的任何东西,我们最终计算出一个结果然后将其丢弃。这将与刚刚做的几乎一样:

evalStatement_ _ (Eval _) = return ()  -- do nothing