Safe conversion to Word8
Take a look at the following snippet:
Prelude> import Data.Word
Prelude> data Foo = Foo Word8 deriving Show
Prelude> Foo 4
Foo 4
Prelude> Foo 44
Foo 44
Prelude> Foo 444
Foo 188
I'm a little surprised that 444 is implicitly converted to 188, as in unsafe C. It looks pretty error prone. What's the idiomatic way to safely deal with such conversions in Haskell?
UPDATE
This seems to be just polymorphic behavior of literals and the modern compiler warns about this. Most importantly, the type system does not allow for such implicit truncation. Foo (444 :: Int)
generates type mismatch, so it is completely safe if the value is known only at runtime.
source to share
A warning was recently added to the GHC to cause such cases. With GHC 7.8.3 I see:
Prelude Data.Word> Foo 444
<interactive>:7:5: Warning:
Literal 444 is out of the Word8 range 0..255
Foo 188
Prelude Data.Word>
And when compiling:
$ ghc so.hs
[1 of 1] Compiling Main ( so.hs, so.o )
so.hs:5:19: Warning: Literal 444 is out of the Word8 range 0..255
So the idiomatic solution is to use the latest version of the most popular compiler.
source to share
I don't know about the idioms, but the problem you are experiencing is basically that the literal gets truncated when it goes out of bounds. Since literals are polymorphic in Num
, and Integral
require Num
, you have functions
fromInteger :: Num a => Integer -> a toInteger :: Integral a => a -> Integer
Therefore, you can always compare them as Integer
before conversion:
-- Don't export the constructor
data Foo = Foo Word8 deriving (Eq, Show)
foo :: Integral a => a -> Maybe Foo
foo x = if xI > mBW8I then Nothing else Just (Foo $ fromInteger xI)
where
xI = toInteger x
mBW8 :: Word8
mBW8 = maxBound
mbW8I = toInteger mBW8
Then you can use foo
as a smart constructor:
> foo 4
Just (Foo 4)
> foo 44
Just (Foo 44)
> foo 444
Nothing
source to share