如何过滤 Maybe 值

How to filter a Maybe value

我正在尝试创建一个函数来验证输入 String -> Maybe Int。我检查输入字符串是否为数字,然后检查该数字是否在范围内。到目前为止我有

validateNumber :: String -> Maybe Int
validateNumber n  = go $ (readMaybe::String -> Maybe Int) n
  where
    go (Just a) = inRange a
    go Nothing  = Nothing

inRange :: Int -> Maybe Int
inRange n
  | n > 0     = Just n
  | otherwise = Nothing

这感觉像是糟糕的代码。这个应该怎么写?

另外,如果我想循环一个函数 returns Nothing,最好的方法是什么:

所以要循环 main 函数,我正在做:

case v of
  Nothing -> main
  Just x  -> {do something}

我会尝试这样的事情(未测试):

validateNumber :: String -> Maybe Int
validateNumber n = case (readMaybe::String -> Maybe Int) n of
    (Just a) -> case n > 0 of
        True  -> Just n
        False -> Nothing
    Nothing  -> Nothing

它更短更简洁。

您可以使用 mfilter 过滤 Maybe 中超出范围的值,而不是显式匹配:

import Control.Monad (mfilter)

validateNumber :: String -> Maybe Int
validateNumber = mfilter (> 0) . readMaybe

这个怎么样?

validateNumber :: String -> Maybe Int
validateNumber n = (readMaybe n) >>= inRange

甚至这样:

validateNumber :: String -> Maybe Int
validateNumber str = do
  n <- readMaybe str
  if n < 0 then Nothing else return n

(避免需要单独的 inRange 函数。)