Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safe conversion to Word8

Tags:

haskell

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 bit surprised that 444 is implicitly converted to 188 like in unsafe C. It looks pretty error-prone to me. What's the idiomatic way to deal with such conversions safely in Haskell?

UPDATE

It seems this is just polymorphic behavior of literals and modern compiler warns about this. The most important is that type system doesn't allow such implicit truncation. Foo (444 :: Int) generates type mismatch, so this is completely safe if value is known in run-time only.

like image 408
Stas Avatar asked Aug 22 '26 17:08

Stas


2 Answers

A warning was recently added to GHC to call out cases such as this. 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.

like image 137
Thomas M. DuBuisson Avatar answered Aug 25 '26 08:08

Thomas M. DuBuisson


I don't know about idiomatic, but the problem you're experiencing basically that a literal is being truncated when it's out of bounds. Since literals are polymorphic on Num, and Integrals require Num as well, you have the functions

fromInteger :: Num a => Integer -> a
toInteger :: Integral a => a -> Integer

So 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
like image 27
bheklilr Avatar answered Aug 25 '26 07:08

bheklilr



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!