
On Monday 16 March 2009 06:40:12 Alexander Dunlap wrote:
Hi all,
I have noticed that in both Data.Binary and Data.Text (which is still experimental, but still), the "decode" functions can be undefined (i.e. bottom) if they encounter malformed input.
What is the preferred way to use these functions in a safe way? For example, if one writes data to a disk using Data.Binary and wants to read it back in at a later date, how can one ensure that it is valid so that Data.Binary does not hit an error? Or do you just have to catch the exception in the IO Monad?
I've used ErrorT monad transformer for decoding. With that it's possible to work around this problem. As downside one is required to do all checks and throw errors manually. It would be nice to have some kind of error handling in Data.Binary How it was done:
import Control.Monad.Error
-- | Get monad with applied to it Error monad transformer type Decoder = ErrorT String Get
-- | Subequipment data data SubEq = SubEq { subeqID :: Int , subeqData :: ByteString }
-- | Abort execution if function evaluates to True dieIf :: (a -> Bool) -> String -> a -> Decoder () dieIf f err x = when (f x) (throwError err)
readSubEq :: Decoder SubEq readSubEq = do lift remaining >>= dieIf (<4) "DATE: Too short subequipment data (<4)" -- Read header len <- liftM (\x -> fromIntegral $ 2*x - 4) $ lift getWord16le s_id <- liftM fromIntegral $ lift getWord16le lift remaining >>= dieIf (< len) "DATE: Too short subequipment data" buf <- lift $ getLazyByteString len return $! SubEq s_id buf
-- Actual decoding decodeSubEq = runGet (runErrorT readSubEq)