read関数は文字列から指定された型のデータを生成します。
型が指定されない場合、read関数はどんな型に変換すれば良いか分からないので例外を発生します。
また、パースにエラーがある場合にも、例外を発生します。
> read "123"::Int -- > 123 -- 型が指定されない場合 > read "3.14" <interactive>:86:1: No instance for (Read a0) arising from a use of `read' The type variable `a0' is ambiguous Possible fix: add a type signature that fixes these type variable(s) Note: there are several potential instances: instance Read GHC.IO.Exception.ExitCode -- Defined in `GHC.IO.Exception' instance Read () -- Defined in `GHC.Read' instance (Read a, Read b) => Read (a, b) -- Defined in `GHC.Read' ...plus 44 others In the expression: read "3.14" In an equation for `it': it = read "3.14" -- パースにエラーがある場合 > read "abc"::Int *** Exception: Prelude.read: no parse
- 例外を発生させるのではなく失敗を含むMaybe型を返して欲しい
例外を補足し、正常にパース出来た場合はJust、パースに失敗した場合はNothingを返すmaybeReadの例がStack Overflowにありました。
maybeRead :: Read a => String -> Maybe a maybeRead s = case reads s of [(x, "")] -> Just x _ -> Nothing
> maybeRead "abc"::Maybe Int -- > Nothing > maybeRead "123"::Maybe Int -- > Just 123 Data.Time Data.Time.Calendar> maybeRead "2000-01-01"::Maybe Day -- > Just 2000-01-01 Data.Time Data.Time.Calendar> maybeRead "abc"::Maybe Day -- > Nothing
- reads 関数が重要な役目を持っているようです。
reads 関数を少しいじってみます。
> reads "123" ::[(Int,String)] -- > [(123,"")] > reads "123 456" ::[(Int,String)] -- > [(123," 456")] > reads "123abc" ::[(Int,String)] -- > [(123,"abc")] > reads "2014-03-24hello,world!" ::[(Day,String)] -- > [(2014-03-24,"hello,world!")]
- try により Either型を返す。
Prelude Control.Exception> try (print (read "123"::Int)) ::IO (Either SomeException ()) 123 -- > Right () Prelude Control.Exception> try (print (read "qwe"::Int)) ::IO (Either SomeException ()) -- > Left Prelude.read: no parse Prelude Control.Exception> try (evaluate (read "123"::Int)) ::IO (Either SomeException Int) -- > Right 123 Prelude Control.Exception> try (evaluate (read "1q23"::Int)) ::IO (Either SomeException Int) -- > Left Prelude.read: no parse
- tryJust, catchJust and handleJust
main = do result <- tryJust selectDivByZero (evaluate $ 5 `div` 0) case result of Left what -> putStrLn $ "Division by " ++ what Right val -> putStrLn $ "The answer was: " ++ show val where selectDivByZero :: ArithException -> Maybe String selectDivByZero DivideByZero = Just "zero" selectDivByZero _ = Nothing