我使用n< - getLine来获取用户价格。我如何检查值是否正确? (价格可以有'。'和数字,但必须大于0)?
不起作用:
isFloat = do
n <- getLine
let val = case reads n of
((v,_):_) -> True
_ -> False
答案 0 :(得分:4)
如果输入始终有效或例外情况正常
如果您让用户以“123.456”的形式输入十进制数字,则只需使用read
将其转换为Float或Double:
n <- getLine
let val = read n
或者在一行中(已导入Control.Monad
):
n <- liftM read getLine
捕获错误输入
如果用户输入无效条目,则上述代码失败并出现异常。如果这是一个问题,那么使用read和listToMaybe
(来自Data.Maybe
):
n <- liftM (fmap fst . listToMaybe . reads) getLine
如果该代码看起来很复杂,那就不要惹恼 - 下面的操作是相同的,但是使用明确的case语句进行所有工作:
n <- getLine
let val = case reads n of
((v,_):_) -> Just v
_ -> Nothing
注意我们模式匹配以获取列表头部中元组的第一个元素,列表的头部为(v,_)
,第一个元素为v
。下划线(_
)仅表示“忽略此点中的值”。
如果浮点不可接受
众所周知,浮动值是近似值,不适合现实世界的财务计算(但也许是家庭作业,取决于您的教授)。在这种情况下,您需要将值读入Rational
(来自Data.Ratio
)。
n <- liftM maybeRational getLine
...
where
maybeRational :: String -> Maybe Rational
maybeRational str =
let (a,b) = break (=='.') str
in liftM2 (%) (readMaybe a) (readMaybe $ drop 1 b)
readMaybe = fmap fst . listToMaybe . reads
答案 1 :(得分:1)
除了TomMD提供的解析建议之外,请考虑使用适当的monad进行错误报告。它允许您方便地链接可能失败的计算,避免在每个步骤上进行显式错误检查。
{-# LANGUAGE FlexibleContexts #-}
import Control.Monad.Error
parsePrice :: MonadError String m => String -> m Double
parsePrice s = do
x <- case reads s of
[(x, "")] -> return x
_ -> throwError "Not a valid real number."
when (x <= 0) $ throwError "Price must be positive."
return x
main = do
n <- getLine
case parsePrice n of
Left err -> putStrLn err
Right x -> putStrLn $ "Price is " ++ show x