如何在Haskell中临时将整数转换为更大的大小?

时间:2014-12-16 05:38:53

标签: haskell casting

我在以下函数中遇到数字换行问题:

f :: Word8 -> Word8 -> Word8
f a b = (a + b) `mod` 255

这个想法是将两个数字加在一起,模数255(注意 255 ,而不是mod 256 )。

显然,f 252 8的答案应该是260 mod 255 = 5,但上面的函数实际上返回4,因为Word8能够仅保留数字,因此252 + 8包裹到4 255.永远不会应用mod函数。

我试过了:

f :: Word8 -> Word8 -> Word8
f a b = (fromIntegral a + fromIntegral b) `mod` 255

认为它会隐式转换为IntegerInt,但事实并非如此。什么是正确的解决方案,以便f不会受到包装问题的困扰并且效率不高?

2 个答案:

答案 0 :(得分:5)

由于您要求它返回Word8,我们可以推断mod的参数都是Word8,因此+的参数两者都是Word8' s,因此fromIntegral实际上被推断为类型Word8 -> Word8 - 可能不是你想要的!

一种解决方法是暂时转换为Integer(或其他任何类型),然后返回Word8

f a b = fromInteger ((fromIntegral a + fromIntegral b) `mod` 255)

另一个解决方案是手动检查是否发生了溢出。

f a b = (sum + if sum < a then 1 else 0) `mod` 255
    where sum = a + b

(这里的最终mod操作确实是必需的,如果sum255,因此没有发生溢出!)

答案 1 :(得分:1)

如果需要,可以深入研究低级Haskell并使用原始操作。我已经Michael Snoyman's answer指出了我的相关问题。在这里,我们不需要缩小结果范围,因为余数操作(remWord#)应该始终提供足够小的数字:

{-# LANGUAGE MagicHash #-}

module Word8Mod where

import GHC.Prim
import GHC.Word

f :: Word8 -> Word8 -> Word8
f (W8# x#) (W8# y#) =
  let z# = plusWord# x# y#
  in W8# (remWord# z# (int2Word# 255#))