【问题标题】:Haskell - Validate integer input from string using readMaybeHaskell - 使用 readMaybe 验证来自字符串的整数输入
【发布时间】:2018-03-19 15:47:07
【问题描述】:

我正在尝试验证来自字符串的整数输入,如果输入字符串正确地将类型更改为整数,我只需要一个布尔结果。我从另一个问题尝试了这种方法:

https://stackoverflow.com/a/30030649/3339668

这是相关代码以及我的导入:

import Data.Char
import Data.List
import Text.Read

checkValidInt :: String -> Bool
checkValidInt strInt
 | readMaybe strInt :: Maybe Int == Nothing = False
 | readMaybe strInt :: Maybe Int /= Nothing = True

但是,我在加载脚本时收到以下错误:

Illegal operator ‘==’ in type ‘Maybe Int == Nothing’
Use TypeOperators to allow operators in types

main.hs:350:38:
Not in scope: type constructor or class ‘Nothing’
A data constructor of that name is in scope; did you mean DataKinds?

main.hs:351:35:
Illegal operator ‘/=’ in type ‘Maybe Int /= Nothing’
  Use TypeOperators to allow operators in types

main.hs:351:38:
Not in scope: type constructor or class ‘Nothing’
A data constructor of that name is in scope; did you mean DataKinds?

那么什么数据类型是Nothing呢?如何检查 Nothing 是否是 readMaybe 的正确结果?

谢谢。

【问题讨论】:

  • 你根本不应该在这里使用==;虽然Maybe a 有一个Eq 实例,但您不需要 在这里使用它。模式匹配就足够了。

标签: validation haskell


【解决方案1】:

我只需要一个布尔结果

可能不会。您需要 Maybe Int 来进行模式匹配,而 readMaybe 已经为您提供了此功能,无需任何进一步处理。

不是这个

if checkValidInt s                -- try reading an Int, but throw it away
   then foo (read s)              -- now really read an Int and use it
   else bar                       -- fall back

你这样做

case readMaybe s of               -- try reading an Int
   Just i   -> foo i              -- use it
   Nothing  -> bar                -- fall back

如果foo 的类型正确,通常不需要显式类型注释;但见下文。

如果你出于某种深不可测的原因,真的需要checkValidInt,你可以基于上述模式

case (readMaybe s) :: Maybe Int of 
   Just _   -> True
   Nothing  -> False

正如另一个答案中所述,maybe 函数将这种模式匹配抽象出来,但我建议尽可能使用显式模式匹配作为练习,以掌握它的窍门。

【讨论】:

  • 我完全同意。这很可能是“布尔盲”的情况,其中所有信息都被简化为布尔值,因为程序员只能理解if 而不是case。最终结果是代码效率较低(字符串被解析两次)、可读性较差(较长)和安全性较低(使用了部分函数)。
【解决方案2】:

这是因为 Haskell 会解释你的

readMaybe strInt :: (Maybe Int == Nothing = False)

作为:

readMaybe strInt :: (Maybe Int == Nothing = False)

这毫无意义。所以你可以通过使用一些括号来帮助 Haskell:

(readMaybe strInt :: Maybe Int) == Nothing = False

你最好不要重复条件,而是使用otherwise,因为如果你重复它,程序将 - 除非优化 - 解析两次,所以:

checkValidInt :: String -> Bool
checkValidInt strInt
 | (readMaybe strInt :: Maybe Int) == Nothing = False
 | otherwise = True

既然你检查一个条件,结果是True,如果条件是False,反之亦然,用守卫是没有用的,我们可以写成:

checkValidInt :: String -> Bool
checkValidInt strInt = Nothing /= (readMaybe strInt :: Maybe Int)

或者我们可以使用模式保护,这可以用于我们无法对包裹在Maybe 中的值类型执行相等检查,所以:

checkValidInt :: String -> Bool
checkValidInt strInt | Just _ <- (readMaybe strInt :: Maybe Int) = True
                     | otherwise = False

或者我们可以使用isJust :: Maybe a -&gt; Bool函数:

checkValidInt :: String -> Bool
checkValidInt strInt = isJust (readMaybe strInt :: Maybe Int)

【讨论】:

  • 谢谢,详细又简洁。
【解决方案3】:

你可以把它改写成

import Data.Char
import Data.List
import Text.Read

checkValidInt :: String -> Bool
checkValidInt strInt =
  case (readMaybe strInt :: Maybe Int) of
    Nothing -> False
    Just _  -> True

【讨论】:

    【解决方案4】:

    这里需要的算法已经在maybe函数后面抽象出来了:

    checkValidInt :: String -> Bool
    checkValidInt = maybe False (const True) . (readMaybe :: String -> Maybe Int)
    

    如果readMaybe 返回Nothing,则maybe 返回False。否则,它只是将const True 应用于生成的Just 值,该值返回True,而不关心Just 包装的内容。请注意,您是专门针对 readMaybe 自身 的类型,而不是其返回值的类型。

    或者,使用导入更简单,

    import Data.Maybe
    checkValidInt :: String -> Bool
    checkValidInt = isJust . (readMaybe :: String -> Maybe Int)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-28
      • 2016-06-12
      相关资源
      最近更新 更多