开发者

Checking that a price value in a string is in the correct format

I use n <- getL开发者_运维问答ine to get from user price. How can I check is value correct ? (Price can have '.' and digits and must be greater than 0) ?


It doesn't work:

isFloat = do
    n <- getLine
    let val = case reads n of
                ((v,_):_) -> True
                _ -> False


If The Input Is Always Valid Or Exceptions Are OK

If you have users entering decimal numbers in the form of "123.456" then this can simply be converted to a Float or Double using read:

n <- getLine
let val = read n

Or in one line (having imported Control.Monad):

n <- liftM read getLine

To Catch Erroneous Input

The above code fails with an exception if the users enter invalid entries. If that's a problem then use reads and listToMaybe (from Data.Maybe):

n <- liftM (fmap fst . listToMaybe . reads) getLine

If that code looks complex then don't sweat it - the below is the same operation but doing all the work with explicit case statements:

n <- getLine
let val = case reads n of
            ((v,_):_) -> Just v
            _ -> Nothing

Notice we pattern match to get the first element of the tuple in the head of the list, The head of the list being (v,_) and the first element is v. The underscore (_) just means "ignore the value in this spot".

If Floating Point Isn't Acceptable

Floating values are well known to be approximate, and not suitable for real world financial computations (but perhaps homework, depending on your professor). In this case you'd want to read the values into a Rational (from 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


In addition to the parsing advice provided by TomMD, consider using the appropriate monad for error reporting. It allows you to conveniently chain computations which can fail, avoiding explicit error checking on every step.

{-# 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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜