
Hi, I'm wondering how usually you parse command line arguments list safely. If the given argument is wrong, the program can still print out some error information instead of giving something like Prelude.read: no parse Let's make the discussion concrete. Suppose we have the following code. -->8----------8<-- import System.Environment data Conf = Conf { number :: Int } parseArgs [] = error "need at least one argument" parseArgs (x:_) = Conf { number = read x } work (Conf { number = n }) = n * (n-1) `div` 2 main = print . work . parseArgs =<< getArgs -->8----------8<-- If the "read x" fails in line 8, the program dies with Prelude.read: no parse What is the standard way to make the error message useful? Xiao-Yong -- c/* __o/* <\ * (__ */\ <

Hi
I'm wondering how usually you parse command line arguments list safely. If the given argument is wrong, the program can still print out some error information instead of giving something like
Either use reads instead, and deal with the case where there is no parse. Or use the safe library, on hackage, and something like: import Safe readNote "please enter a number" x Where if x is "test", you'll get: Program error: Prelude.read: no parse, please enter a number, on "test" Or use readDef: readDef (error "Please enter a number") x Which will just give you: Program error: Please enter a number Or, readMay, which will return a Nothing if you fail, which you can deal with as you wish. Thanks Neil

xj2106:
Hi,
I'm wondering how usually you parse command line arguments list safely. If the given argument is wrong, the program can still print out some error information instead of giving something like
Prelude.read: no parse
Let's make the discussion concrete. Suppose we have the following code.
-->8----------8<-- import System.Environment
data Conf = Conf { number :: Int }
parseArgs [] = error "need at least one argument" parseArgs (x:_) = Conf { number = read x }
work (Conf { number = n }) = n * (n-1) `div` 2
main = print . work . parseArgs =<< getArgs -->8----------8<--
If the "read x" fails in line 8, the program dies with
Prelude.read: no parse
What is the standard way to make the error message useful?
Xiao-Yong --
The main thing is to define a safe read. This will be in the base library soon, maybeRead :: Read a => String -> Maybe a maybeRead s = case reads s of [(x, "")] -> Just x _ -> Nothing Then you can pattern match on the failure case as Nothing. Cheers, Don

Don Stewart
The main thing is to define a safe read. This will be in the base library soon,
maybeRead :: Read a => String -> Maybe a maybeRead s = case reads s of [(x, "")] -> Just x _ -> Nothing
Then you can pattern match on the failure case as Nothing.
When will it be in the base library? X-Y -- c/* __o/* <\ * (__ */\ <

On Saturday 21 June 2008, Don Stewart wrote:
maybeRead :: Read a => String -> Maybe a maybeRead s = case reads s of [(x, "")] -> Just x _ -> Nothing
Note, if you want to match the behavior of read, you'll probably want something like: maybeRead :: Read a => String -> Maybe a maybeRead s = case reads s of [(x, str)] | all isSpace str -> Just x _ -> Nothing Otherwise, trailing spaces will yield a bad parse. -- Dan

On Sat, 21 Jun 2008, Xiao-Yong Jin wrote:
Hi,
I'm wondering how usually you parse command line arguments list safely. If the given argument is wrong, the program can still print out some error information instead of giving something like
Prelude.read: no parse
It's generally not a good idea to call 'read' on user data. 'read' expects well-formed input. Calling 'read' with other input is a programming _error_. If the user enters garbage, this is an _exception_ and this must be handled with 'reads' or 'maybeRead' as others suggested. http://www.haskell.org/haskellwiki/Error http://www.haskell.org/haskellwiki/Exception

I'm wondering how usually you parse command line arguments list safely.
Prelude.read: no parse
It's generally not a good idea to call 'read' on user data.
There is (at least one) proper parsing library intended as a direct replacement for Read: http://www.cs.york.ac.uk/fp/polyparse/haddock/Text-Parse.html The basic idea is that the function 'parse' replaces 'read', and to use it at any specific type T: (runParser parse) :: String -> (Either String T, String) You get back either an error message or the value, along with the remaining unparsed text. Instances of the Parse class are defined for all Prelude types, and you can easily derive instances for any of your own types, using the DrIFT tool. Parse is assumed to be an inverse of Show, that is, the derived instances of Parse will read back a canonically derived Show value. Another benefit of using a real parser library is that you can plumb together several parsers quickly if you need to. e.g. runParser (exactly 3 parse) :: String -> (Either String [T], String) Regards, Malcolm
participants (6)
-
Dan Doel
-
Don Stewart
-
Henning Thielemann
-
Malcolm Wallace
-
Neil Mitchell
-
Xiao-Yong Jin