安全转换为Word8

时间:2014-09-08 19:58:02

标签: haskell

请看下面的代码:

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

我有点惊讶444被隐式转换为188,就像在不安全的C中一样。它看起来很容易出错。在Haskell中安全处理此类转换的惯用方法是什么?

更新

这似乎只是文字的多态行为,现代编译器对此发出警告。最重要的是类型系统不允许这种隐式截断。 Foo (444 :: Int)生成类型不匹配,因此如果仅在运行时知道值,则这是完全安全的。

2 个答案:

答案 0 :(得分:6)

最近向GHC发出了一个警告,要求调出此类案件。使用GHC 7.8.3,我看到:

Prelude Data.Word> Foo 444

<interactive>:7:5: Warning:
    Literal 444 is out of the Word8 range 0..255
Foo 188
Prelude Data.Word> 

编译时:

$ 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

因此,惯用的解决方案是使用最流行的编译器的最新版本。

答案 1 :(得分:2)

我不知道惯用语,但是您遇到的问题基本上是文字在超出范围时被截断。由于文字在Num上是多态的,而Integral也需要Num,因此你有函数

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

因此,您始终可以在转化前将其比作Integer

-- 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

然后您可以使用foo作为智能构造函数:

> foo 4
Just (Foo 4)
> foo 44
Just (Foo 44)
> foo 444
Nothing