3

我在 Haskell 中编写了一个简单的程序,可以玩The Rust Programming Language book 中描述的猜谜游戏

它是这样工作的:程序将生成一个介于 1 和 100 之间的随机整数。然后它会提示玩家输入猜测。输入猜测值后,会提示猜测值是过低还是过高。如果猜对了,游戏将打印祝贺并退出。

这是我写的:

import Control.Monad (when)
import System.Random (randomRIO)

-- | Check if the guess is correct, otherwise provide a hint
respond :: Int -> Int -> String
respond correct guess
  | guess > correct = "Smaller than " ++ show guess
  | guess < correct = "Larger than " ++ show guess
  | guess == correct = "Correct! " ++ show correct

-- | Main game loop; prompt for input and repeat until guessed correctly
play :: Int -> IO ()
play x = do
  putStr "Guess: "
  guess <- read <$> getLine
  putStrLn $ respond x guess
  when (guess /= x) $ play x

-- | Start the game with a random number between 1 and 100
main :: IO ()
main = play =<< randomRIO (1, 100)

该代码有效,但 GHC 给了我一个警告,"Pattern match(es) are non exhaustive. In an equation for 'respond': Patterns not matched: _ _"

我用这两个下划线来表示Ints我作为函数参数的两个respond。我不明白的是我没有涵盖哪种情况。那些不是Maybe Ints 或任何特殊的东西——该函数需要两个 valid Ints,所以我只需要处理整数——而且我认为没有任何数字不能被视为大于、小于或等于另一个?

这只是 GHC 假设我没有涵盖所有情况,因为我没有添加最后的otherwise =后卫吗?即使它在逻辑上涵盖了所有情况。


另外,如果您对如何编写更惯用的 Haskell 有任何提示,我将不胜感激。我还在学习基础知识。

4

2 回答 2

7

GHC 根本不知道 , 或 之一a > b必须a < b评估a == bTrue。(实际上,可以编写一个Ord违反这个假设的实例——尽管大多数程序员不会考虑这样做,当然 forInt在这方面表现得很好。)

您可以通过使用完整的模式匹配来让 GHC 清楚地看到您已经涵盖了所有情况,例如

respond correct guess = case compare guess correct of
    GT -> ...
    LT -> ...
    EQ -> ...

GHC 在其穷举检查器中也有一个特殊情况,用于保护otherwiseTrue,因此您可以添加(或替换)其中一个保护作为替代解决方案。

respond correct guess
    | guess > correct = ...
    | guess < correct = ...
    | otherwise = ...
于 2017-09-22T00:17:00.310 回答
3

编译器只进行静态语义分析。这无法看出这三种情况涵盖了所有可能的输入,因为运算符的含义是在运行时确定的。

您的代码可证明是正确的。如果您想避免 GHC 的警告,您可以将最终条件更改为otherwise.

于 2017-09-22T00:16:30.933 回答