模式x*y中的解析错误(case语句)

Jam*_*ood 1 haskell syntax-error

我有这个代码:

module BalancedTwoDozenMultDrill where
import BalancedTwoDozenLib
myRandoms :: Int -> IO [Int]
myRandoms n = let x = 24^n `div` 2 in randomRs (-x,x) <$> getStdGen
drill :: [Int] -> IO ()
drill (x:y:rs) = do
    putStr $ showInt x ++ " × " ++ showInt y ++ " = "
    a <- getLine
    case a of
        "" -> return ()
        showInt (x * y) -> do   -- <= here
            putStrLn "Correct"
            drill rs
        _ -> do
            putStrLn $ "Wrong; " ++ showInt (x * y)
            drill rs
main :: IO [Int]
main = drill =<< myRandoms =<< readLn
Run Code Online (Sandbox Code Playgroud)

并得到错误:

BalancedTwoDozenMultDrill.hs:11:18: Parse error in pattern: x * y
Run Code Online (Sandbox Code Playgroud)

但是,用以下内容替换部分case语句:

    -- ...stuff
    let i = showInt (x * y)
    case a of
        "" -> return ()
        i -> do
        -- stuff...
Run Code Online (Sandbox Code Playgroud)

使其解析(它转到"不在范围内"错误,我可以修复).我看到第一个片段错误的唯一原因是有功能应用正在进行中.在case语句中我不能使用普通函数应用程序来替代它吗?

bhe*_*ilr 6

如果在case语句中有模式,则必须遵循与函数参数模式匹配相同的规则.只能_匹配文字,构造函数和通配符,而不能匹配函数应用程序.相反,你可以做更多的事情

a <- getLine
let xyStr = showInt (x * y)        -- Avoid recomputation with a let binding
when (not $ null a) $ do
    if a == xyStr
        then do
            putStrLn "Correct"
            drill rs
        else do
            putStrLn $ "Wrong; " ++ xyStr
            drill rs
Run Code Online (Sandbox Code Playgroud)

你需要导入whenControl.Monad,虽然.


你必须在case语句中遵循与函数定义中的模式匹配相同的规则的原因是因为编译器实际上转换了像

head :: [a] -> a
head (x:xs) = x
head _ = error "Prelude.head: empty list"
Run Code Online (Sandbox Code Playgroud)

head :: [a] -> a
head list = case list of
    (x:xs) -> x
    _      -> error "Prelude.head: empty list"
Run Code Online (Sandbox Code Playgroud)

我们拥有前一版本的唯一原因是方便,它通常会使代码看起来更漂亮.

链接应该能够为您提供有关什么是有效模式匹配结构的更全面的解释.


你遇到的另一个问题是试图showInt (x * y)i哪里替换let i = showInt (x * y).执行此操作时,首先将值绑定showInt (x * y)到名称i,然后在case语句中使用模式

"" -> ...
i  -> ...
_  -> ...
Run Code Online (Sandbox Code Playgroud)

所以现在你的模式是i,它将在之后表现得像一个包罗万象的模式"".这将重新绑定该icase语句范围的名称.

要记住的一个好规则是,您不能对运行时获得的值进行模式匹配,您必须检查相等或其他比较操作.

  • @JamesWood我想你可以这样说,但从语法上来说,编译器将案例模式和参数模式看作同一个东西.一个更逻辑正确的语句将是"你必须遵循函数定义中的相同规则的原因,因为编译器将函数定义转换为case语句",但AFAIK模式是Haskell中的模式,它们被对待你可以在任何地方使用它们.这包括let语句,monadic绑定操作和列表推导. (2认同)