Haskell中如何为非整数输入返回错误信息(含闰年函数场景)
扩展闰年判断函数支持Float/Double输入,及Haskell非整数输入错误处理方案
嘿,我来帮你搞定这个问题,同时聊聊Haskell里处理非整数输入的几种常用思路~
一、实现支持多数值类型的闰年判断函数
Haskell是强类型语言,要让函数能接受Integer、Float、Double这些不同数值类型,我们可以借助**类型类(Typeclass)**来实现灵活的类型约束。这里用RealFrac类型类就很合适——它包含了所有带小数部分的数值类型,还提供了properFraction函数可以把数值拆成整数部分和小数部分,刚好用来判断输入是否为整数。
简洁的守卫写法实现
days_in_Year :: RealFrac a => a -> String days_in_Year year | frac /= 0 = "Invalid Input" | intYear `mod` 400 == 0 = "Leap Year" | intYear `mod` 100 == 0 = "Non-Leap Year" | intYear `mod` 4 == 0 = "Leap Year" | otherwise = "Non-Leap Year" where (intYear, frac) = properFraction year
测试效果
- 整数输入:
days_in_Year 2018→ 返回"Non-Leap Year" - 整数型浮点数:
days_in_Year 2020.0→ 返回"Leap Year" - 非整数浮点数:
days_in_Year 2018.5→ 返回"Invalid Input" - 整百年输入:
days_in_Year 1900.0→ 返回"Non-Leap Year"
二、Haskell中处理非整数输入的常见方法
除了上面的类型类方案,还有几种不同的思路可以处理非整数输入的错误情况:
1. 显式重载不同类型的函数
如果你不想用类型类,也可以为每个目标类型单独定义函数,利用Haskell的函数重载特性:
-- 原有的Integer类型实现 days_in_Year :: Integer -> String days_in_Year year | year `mod` 400 == 0 = "Leap Year" | year `mod` 100 == 0 = "Non-Leap Year" | year `mod` 4 == 0 = "Leap Year" | otherwise = "Non-Leap Year" -- Double类型的处理 days_in_Year :: Double -> String days_in_Year year | year == fromInteger (round year) = days_in_Year (round year) | otherwise = "Invalid Input" -- Float类型的处理 days_in_Year :: Float -> String days_in_Year year | year == fromInteger (round year) = days_in_Year (round year) | otherwise = "Invalid Input"
这种方式需要为每个类型写单独的实现,适合需要针对不同类型做特殊逻辑的场景,但代码冗余度会高一些。
2. 返回Maybe/Either类型(函数式错误处理)
如果想更贴合Haskell的函数式风格,推荐用Maybe或Either类型来封装结果,把错误信息和正常结果明确区分开:
days_in_Year :: RealFrac a => a -> Either String String days_in_Year year | frac /= 0 = Left "Invalid Input: Input must be an integer" | intYear `mod` 400 == 0 = Right "Leap Year" | intYear `mod` 100 == 0 = Right "Non-Leap Year" | intYear `mod` 4 == 0 = Right "Leap Year" | otherwise = Right "Non-Leap Year" where (intYear, frac) = properFraction year
调用时可以用模式匹配处理两种情况:
case days_in_Year 2018.5 of Left errMsg -> putStrLn $ "Error: " ++ errMsg Right result -> putStrLn $ "Result: " ++ result
这种方式的好处是错误处理更安全、更清晰,避免了字符串返回的模糊性。
3. 抛出异常(谨慎使用)
虽然不推荐在Haskell中滥用异常,但如果场景需要,可以用error函数直接抛出异常:
days_in_Year :: RealFrac a => a -> String days_in_Year year | frac /= 0 = error "Invalid Input: Not an integer value" | intYear `mod` 400 == 0 = "Leap Year" | intYear `mod` 100 == 0 = "Non-Leap Year" | intYear `mod` 4 == 0 = "Leap Year" | otherwise = "Non-Leap Year" where (intYear, frac) = properFraction year
注意:error抛出的异常是不可恢复的(除非用catch等函数捕获),所以只适合确实需要终止程序的错误场景,日常业务逻辑更推荐用Either或Maybe。
内容的提问来源于stack exchange,提问作者Zarathustra Van Bommel
相关产品推荐
相关产品推荐

