简体   繁体   English

Haskell,如何用 case-of 语句替换嵌套的 if?

[英]Haskell, how to replace nested if with a case-of statement?

I'm starting to learn haskell and I'm solving some simple programming challenges.我开始学习 Haskell,我正在解决一些简单的编程挑战。 So my current problem right now is just printing some text based on the value being passed:所以我现在的问题只是根据传递的值打印一些文本:

main = do
  n <- readLn :: IO Int
  if n `mod` 2 > 0
      then putStrLn "Weird"
      else if n > 1 && n < 6
          then putStrLn "Not Weird"
          else if n > 5 && n < 21
              then putStrLn "Weird"
              else putStrLn "Not Weird"

However I think this is fairly ugly, is there someway I could replace the nested if structure with a more elegant pattern matching?但是我认为这相当丑陋,有没有办法用更优雅的模式匹配替换嵌套的 if 结构?

I've tried:我试过了:

main :: IO()
main = do
    n <- readLn :: IO Int
    case n of
        n `mod` 2 /= 0 -> putStrLn "Weird"
        n >= 2 && N <= 5 -> putStrLn "Not Weird"
        n >= 6 && N <= 20 -> putStrLn "Weird"
        n > 20 -> putStrLn "Not Weird"

but I get a compile error.但我收到编译错误。

Edit: Final solution编辑:最终解决方案

check :: Int -> String
check n
    | (n `mod` 2 /= 0) = "Weird"
    | (n >= 2) && (n <= 5) = "Not Weird"
    | (n >= 6) && (n <= 20) = "Weird"
    | otherwise = "Not Weird"

main :: IO()
main = do
    n <- readLn :: IO Int
    putStrLn (check n)

You need to use guards if you have boolean expressions (conditions), instead of actual patterns.如果您有布尔表达式(条件),而不是实际模式,则需要使用守卫。

main :: IO()
main = do
    n <- readLn :: IO Int
    case () of
       _ | n `mod` 2 /= 0 -> putStrLn "Weird"
         | n >= 2 && n <= 5 -> putStrLn "Not Weird"
         | n >= 6 && n <= 20 -> putStrLn "Weird"
         | n > 20 -> putStrLn "Not Weird"

Consider using otherwise in the last case: assuming you want to catch everything else, it's faster and suppresses a GHC warning about non-exhaustiveness.考虑在最后一种情况下使用otherwise :假设您想捕获其他所有内容,它会更快并抑制关于非穷尽性的 GHC 警告。

A "multiway if" can also be used as an alternative, but it requires an extension. “multiway if”也可以用作替代方案,但它需要扩展。

A case expression [Haskell-report] deals with patterns. case表达式[Haskell-report]处理模式。 An expression like n `mod` 2 /= 0 is not a pattern.n `mod` 2 /= 0这样的表达式不是模式。

I propose to define a helper function, and use guards :我建议定义一个辅助函数,并使用guards

tmp :: Int -> String
tmp n | n `mod` 2 /= 0 = "Weird"
      | n >= 2 && N <= 5 = "Not Weird"
      | n >= 6 && N <= 20 = "Weird"
      | n > 20 = "Not Weird"
      | otherwise = …

You will still need to define a value for the otherwise case, in case n <= 0 .您仍然需要为otherwise情况定义一个值,以防n <= 0

We can then use this with:然后我们可以将其用于:

main = do
    n <- readLn
    putStrLn (tmp n)

"multiway if" was mentioned in chi's answer but not explained and I think it's useful to know about for such cases. chi 的回答中提到了“multiway if”,但没有解释,我认为了解这种情况很有用。 Enabling the MultiWayIf extension (eg by writing {-# LANGUAGE MultiWayIf #-} at the top of the file) allows you to write启用MultiWayIf扩展(例如通过在文件顶部写入{-# LANGUAGE MultiWayIf #-} )允许您编写

if | (n `mod` 2 /= 0) -> putStrLn "Weird"
   | (n >= 2) && (n <= 5) -> putStrLn "Not Weird"
   | (n >= 6) && (n <= 20) -> putStrLn "Weird"
   | otherwise -> putStrLn "Not Weird"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM