1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
|
{-
Copyright (C) 2009-2011 John Goerzen <jgoerzen@complete.org>
All rights reserved.
For license and copyright information, see the file LICENSE
-}
{- |
Module : Data.Convertible.Base
Copyright : Copyright (C) 2009-2011 John Goerzen
License : BSD3
Maintainer : John Goerzen <jgoerzen@complete.org>
Stability : provisional
Portability: portable
-}
module Data.Convertible.Base( -- * The conversion process
convert,
Convertible(..),
-- * Handling the results
ConvertResult,
ConvertError(..),
convError,
prettyConvertError
)
where
import Control.Monad.Error
import Data.Typeable
{- | The result of a safe conversion via 'safeConvert'. -}
type ConvertResult a = Either ConvertError a
----------------------------------------------------------------------
-- Conversions
----------------------------------------------------------------------
{- | A typeclass that represents something that can be converted.
A @Convertible a b@ instance represents an @a@ that can be converted to a @b@. -}
class Convertible a b where
{- | Convert @a@ to @b@, returning Right on success and Left on error.
For a simpler interface, see 'convert'. -}
safeConvert :: a -> ConvertResult b
{-
{- | Any type can be converted to itself. -}
instance Convertible a a where
safeConvert x = return x
-}
{-
{- | Lists of any convertible type can be converted. -}
instance Convertible a b => Convertible [a] [b] where
safeConvert = mapM safeConvert
-}
{- | Convert from one type of data to another. Raises an exception if there is
an error with the conversion. For a function that does not raise an exception
in that case, see 'safeConvert'. -}
convert :: Convertible a b => a -> b
convert x =
case safeConvert x of
Left e -> error (prettyConvertError e)
Right r -> r
{-
instance Convertible Int Double where
safeConvert = return . fromIntegral
instance Convertible Double Int where
safeConvert = return . truncate -- could do bounds checking here
instance Convertible Integer Double where
safeConvert = return . fromIntegral
instance Convertible Double Integer where
safeConvert = return . truncate
-}
----------------------------------------------------------------------
-- Error Handling
----------------------------------------------------------------------
{- | How we indicate that there was an error. -}
data ConvertError = ConvertError {
convSourceValue :: String,
convSourceType :: String,
convDestType :: String,
convErrorMessage :: String}
deriving (Eq, Read, Show)
instance Error ConvertError where
strMsg x = ConvertError "(unknown)" "(unknown)" "(unknown)" x
convError' :: (Show a, Typeable a, Typeable b) =>
String -> a -> b -> ConvertResult b
convError' msg inpval retval =
Left $ ConvertError {
convSourceValue = show inpval,
convSourceType = show . typeOf $ inpval,
convDestType = show . typeOf $ retval,
convErrorMessage = msg}
convError :: (Show a, Typeable a, Typeable b) =>
String -> a -> ConvertResult b
convError msg inpval =
convError' msg inpval undefined
prettyConvertError :: ConvertError -> String
prettyConvertError (ConvertError sv st dt em) =
"Convertible: error converting source data " ++ sv ++ " of type " ++ st
++ " to type " ++ dt ++ ": " ++ em
|